From a106025015c8d24af6518aba3ac19c4dc9098b7c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 6 Aug 2010 14:51:10 +0200 Subject: HID: picolcd: testing the wrong variable "ref_cnt" is a point to the reference count and it's non-null. We really want to test the reference count itself. Signed-off-by: Dan Carpenter Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c index 346f0e3..c0bdeba 100644 --- a/drivers/hid/hid-picolcd.c +++ b/drivers/hid/hid-picolcd.c @@ -547,7 +547,7 @@ static void picolcd_fb_destroy(struct fb_info *info) ref_cnt--; mutex_lock(&info->lock); (*ref_cnt)--; - may_release = !ref_cnt; + may_release = !*ref_cnt; mutex_unlock(&info->lock); if (may_release) { framebuffer_release(info); -- cgit v0.10.2 From 1778ca298b06ec86af5fc9603447c379cbfb477b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Pr=C3=A9mont?= Date: Fri, 6 Aug 2010 10:08:04 +0200 Subject: HID: picolcd: correct ordering of framebuffer freeing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the free() ordering (which was never reached due to wrong check). Signed-off-by: Bruno PrĂ©mont Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c index c0bdeba..bc2e077 100644 --- a/drivers/hid/hid-picolcd.c +++ b/drivers/hid/hid-picolcd.c @@ -550,8 +550,8 @@ static void picolcd_fb_destroy(struct fb_info *info) may_release = !*ref_cnt; mutex_unlock(&info->lock); if (may_release) { - framebuffer_release(info); vfree((u8 *)info->fix.smem_start); + framebuffer_release(info); } } -- cgit v0.10.2 From 1b5ad24878b7e5a543b98c5d2f8c0d8c0dd3088f Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sat, 7 Aug 2010 14:29:22 +0200 Subject: slub: add missing __percpu markup in mm/slub_def.h kmem_cache->cpu_slab is a percpu pointer but was missing __percpu markup. Add it. Signed-off-by: Namhyung Kim Acked-by: Tejun Heo Signed-off-by: Pekka Enberg diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h index 6447a72..5ec4bc0 100644 --- a/include/linux/slub_def.h +++ b/include/linux/slub_def.h @@ -68,7 +68,7 @@ struct kmem_cache_order_objects { * Slab cache management. */ struct kmem_cache { - struct kmem_cache_cpu *cpu_slab; + struct kmem_cache_cpu __percpu *cpu_slab; /* Used for retriving partial slabs etc */ unsigned long flags; int size; /* The size of an object including meta data */ -- cgit v0.10.2 From 1ab335d8f85792e3b107ff8237d53cf64db714df Mon Sep 17 00:00:00 2001 From: Carsten Otte Date: Fri, 6 Aug 2010 18:19:22 +0200 Subject: slab: fix object alignment This patch fixes alignment of slab objects in case CONFIG_DEBUG_PAGEALLOC is active. Before this spot in kmem_cache_create, we have this situation: - align contains the required alignment of the object - cachep->obj_offset is 0 or equals align in case of CONFIG_DEBUG_SLAB - size equals the size of the object, or object plus trailing redzone in case of CONFIG_DEBUG_SLAB This spot tries to fill one page per object if the object is in certain size limits, however setting obj_offset to PAGE_SIZE - size does break the object alignment since size may not be aligned with the required alignment. This patch simply adds an ALIGN(size, align) to the equation and fixes the object size detection accordingly. This code in drivers/s390/cio/qdio_setup_init has lead to incorrectly aligned slab objects (sizeof(struct qdio_q) equals 1792): qdio_q_cache = kmem_cache_create("qdio_q", sizeof(struct qdio_q), 256, 0, NULL); Acked-by: Christoph Lameter Signed-off-by: Carsten Otte Signed-off-by: Pekka Enberg diff --git a/mm/slab.c b/mm/slab.c index 736e497..dd41b74 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -2330,8 +2330,8 @@ kmem_cache_create (const char *name, size_t size, size_t align, } #if FORCED_DEBUG && defined(CONFIG_DEBUG_PAGEALLOC) if (size >= malloc_sizes[INDEX_L3 + 1].cs_size - && cachep->obj_size > cache_line_size() && size < PAGE_SIZE) { - cachep->obj_offset += PAGE_SIZE - size; + && cachep->obj_size > cache_line_size() && ALIGN(size, align) < PAGE_SIZE) { + cachep->obj_offset += PAGE_SIZE - ALIGN(size, align); size = PAGE_SIZE; } #endif -- cgit v0.10.2 From 3e33d94df7f5c94adb09139b5d816a248d703a36 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 11:17:25 +0100 Subject: drm/i915: Remove useless message when disabling "Big FIFO" on PineView As we already have appropriate debug and warnings when we activate and deactivate the self-refresh FIFO, having a further INFO is just annoying. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1e5e0d3..1490a8c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2930,13 +2930,9 @@ static struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, int is_ddr3, static void pineview_disable_cxsr(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 reg; /* deactivate cxsr */ - reg = I915_READ(DSPFW3); - reg &= ~(PINEVIEW_SELF_REFRESH_EN); - I915_WRITE(DSPFW3, reg); - DRM_INFO("Big FIFO is disabled\n"); + I915_WRITE(DSPFW3, I915_READ(DSPFW3) & ~PINEVIEW_SELF_REFRESH_EN); } /* @@ -3075,9 +3071,8 @@ static void pineview_update_wm(struct drm_device *dev, int planea_clock, DRM_DEBUG_KMS("DSPFW3 register is %x\n", reg); /* activate cxsr */ - reg = I915_READ(DSPFW3); - reg |= PINEVIEW_SELF_REFRESH_EN; - I915_WRITE(DSPFW3, reg); + I915_WRITE(DSPFW3, + I915_READ(DSPFW3) | PINEVIEW_SELF_REFRESH_EN); DRM_DEBUG_KMS("Self-refresh is enabled\n"); } else { pineview_disable_cxsr(dev); -- cgit v0.10.2 From 94113cecaea5067a0f7e1135abbd92cf2c297d42 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 11:25:21 +0100 Subject: drm/i915: Do not clobber the contents of TRANS_DP_CTL when enabling. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 281db6e..97a35a4 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2928,6 +2928,7 @@ #define TRANS_DP_VSYNC_ACTIVE_LOW 0 #define TRANS_DP_HSYNC_ACTIVE_HIGH (1<<3) #define TRANS_DP_HSYNC_ACTIVE_LOW 0 +#define TRANS_DP_SYNC_MASK (3<<3) /* SNB eDP training params */ /* SNB A-stepping */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1490a8c..c7f19ec 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2097,9 +2097,10 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) int reg; reg = I915_READ(trans_dp_ctl); - reg &= ~TRANS_DP_PORT_SEL_MASK; - reg = TRANS_DP_OUTPUT_ENABLE | - TRANS_DP_ENH_FRAMING; + reg &= ~(TRANS_DP_PORT_SEL_MASK | + TRANS_DP_SYNC_MASK); + reg |= (TRANS_DP_OUTPUT_ENABLE | + TRANS_DP_ENH_FRAMING); if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC) reg |= TRANS_DP_HSYNC_ACTIVE_HIGH; -- cgit v0.10.2 From ea5b213ad4b161463e76b63dbb115ea20e2200f0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 13:50:23 +0100 Subject: drm/i915: Subclass intel_encoder. Subclass intel_encoder to reduce the pointer dance through intel_encoder->dev_priv. 10 files changed, 896 insertions(+), 997 deletions(-) Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/dvo.h b/drivers/gpu/drm/i915/dvo.h index 0d6ff64..8c2ad01 100644 --- a/drivers/gpu/drm/i915/dvo.h +++ b/drivers/gpu/drm/i915/dvo.h @@ -30,20 +30,17 @@ #include "intel_drv.h" struct intel_dvo_device { - char *name; + const char *name; int type; /* DVOA/B/C output register */ u32 dvo_reg; /* GPIO register used for i2c bus to control this device */ u32 gpio; int slave_addr; - struct i2c_adapter *i2c_bus; const struct intel_dvo_dev_ops *dev_ops; void *dev_priv; - - struct drm_display_mode *panel_fixed_mode; - bool panel_wants_dither; + struct i2c_adapter *i2c_bus; }; struct intel_dvo_dev_ops { diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index ee0732b..cfcf854 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -508,17 +508,8 @@ static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs .best_encoder = intel_attached_encoder, }; -static void intel_crt_enc_destroy(struct drm_encoder *encoder) -{ - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - - intel_i2c_destroy(intel_encoder->ddc_bus); - drm_encoder_cleanup(encoder); - kfree(intel_encoder); -} - static const struct drm_encoder_funcs intel_crt_enc_funcs = { - .destroy = intel_crt_enc_destroy, + .destroy = intel_encoder_destroy, }; void intel_crt_init(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c7f19ec..9839494 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2537,6 +2537,20 @@ void intel_encoder_commit (struct drm_encoder *encoder) encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); } +void intel_encoder_destroy(struct drm_encoder *encoder) +{ + struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); + + if (intel_encoder->ddc_bus) + intel_i2c_destroy(intel_encoder->ddc_bus); + + if (intel_encoder->i2c_bus) + intel_i2c_destroy(intel_encoder->i2c_bus); + + drm_encoder_cleanup(encoder); + kfree(intel_encoder); +} + static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 40be1fa..c4c5868 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -42,10 +42,11 @@ #define DP_LINK_CONFIGURATION_SIZE 9 -#define IS_eDP(i) ((i)->type == INTEL_OUTPUT_EDP) -#define IS_PCH_eDP(dp_priv) ((dp_priv)->is_pch_edp) +#define IS_eDP(i) ((i)->base.type == INTEL_OUTPUT_EDP) +#define IS_PCH_eDP(i) ((i)->is_pch_edp) -struct intel_dp_priv { +struct intel_dp { + struct intel_encoder base; uint32_t output_reg; uint32_t DP; uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE]; @@ -54,40 +55,39 @@ struct intel_dp_priv { uint8_t link_bw; uint8_t lane_count; uint8_t dpcd[4]; - struct intel_encoder *intel_encoder; struct i2c_adapter adapter; struct i2c_algo_dp_aux_data algo; bool is_pch_edp; }; -static void -intel_dp_link_train(struct intel_encoder *intel_encoder, uint32_t DP, - uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE]); +static struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder) +{ + return container_of(enc_to_intel_encoder(encoder), struct intel_dp, base); +} -static void -intel_dp_link_down(struct intel_encoder *intel_encoder, uint32_t DP); +static void intel_dp_link_train(struct intel_dp *intel_dp); +static void intel_dp_link_down(struct intel_dp *intel_dp); void intel_edp_link_config (struct intel_encoder *intel_encoder, - int *lane_num, int *link_bw) + int *lane_num, int *link_bw) { - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; + struct intel_dp *intel_dp = container_of(intel_encoder, struct intel_dp, base); - *lane_num = dp_priv->lane_count; - if (dp_priv->link_bw == DP_LINK_BW_1_62) + *lane_num = intel_dp->lane_count; + if (intel_dp->link_bw == DP_LINK_BW_1_62) *link_bw = 162000; - else if (dp_priv->link_bw == DP_LINK_BW_2_7) + else if (intel_dp->link_bw == DP_LINK_BW_2_7) *link_bw = 270000; } static int -intel_dp_max_lane_count(struct intel_encoder *intel_encoder) +intel_dp_max_lane_count(struct intel_dp *intel_dp) { - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; int max_lane_count = 4; - if (dp_priv->dpcd[0] >= 0x11) { - max_lane_count = dp_priv->dpcd[2] & 0x1f; + if (intel_dp->dpcd[0] >= 0x11) { + max_lane_count = intel_dp->dpcd[2] & 0x1f; switch (max_lane_count) { case 1: case 2: case 4: break; @@ -99,10 +99,9 @@ intel_dp_max_lane_count(struct intel_encoder *intel_encoder) } static int -intel_dp_max_link_bw(struct intel_encoder *intel_encoder) +intel_dp_max_link_bw(struct intel_dp *intel_dp) { - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; - int max_link_bw = dp_priv->dpcd[1]; + int max_link_bw = intel_dp->dpcd[1]; switch (max_link_bw) { case DP_LINK_BW_1_62: @@ -126,13 +125,11 @@ intel_dp_link_clock(uint8_t link_bw) /* I think this is a fiction */ static int -intel_dp_link_required(struct drm_device *dev, - struct intel_encoder *intel_encoder, int pixel_clock) +intel_dp_link_required(struct drm_device *dev, struct intel_dp *intel_dp, int pixel_clock) { struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; - if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) + if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) return (pixel_clock * dev_priv->edp_bpp) / 8; else return pixel_clock * 3; @@ -149,14 +146,13 @@ intel_dp_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; - int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_encoder)); - int max_lanes = intel_dp_max_lane_count(intel_encoder); + int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_dp)); + int max_lanes = intel_dp_max_lane_count(intel_dp); - if ((IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) && + if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) && dev_priv->panel_fixed_mode) { if (mode->hdisplay > dev_priv->panel_fixed_mode->hdisplay) return MODE_PANEL; @@ -167,8 +163,8 @@ intel_dp_mode_valid(struct drm_connector *connector, /* only refuse the mode on non eDP since we have seen some wierd eDP panels which are outside spec tolerances but somehow work by magic */ - if (!IS_eDP(intel_encoder) && - (intel_dp_link_required(connector->dev, intel_encoder, mode->clock) + if (!IS_eDP(intel_dp) && + (intel_dp_link_required(connector->dev, intel_dp, mode->clock) > intel_dp_max_data_rate(max_link_clock, max_lanes))) return MODE_CLOCK_HIGH; @@ -232,13 +228,12 @@ intel_hrawclk(struct drm_device *dev) } static int -intel_dp_aux_ch(struct intel_encoder *intel_encoder, +intel_dp_aux_ch(struct intel_dp *intel_dp, uint8_t *send, int send_bytes, uint8_t *recv, int recv_size) { - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; - uint32_t output_reg = dp_priv->output_reg; - struct drm_device *dev = intel_encoder->enc.dev; + uint32_t output_reg = intel_dp->output_reg; + struct drm_device *dev = intel_dp->base.enc.dev; struct drm_i915_private *dev_priv = dev->dev_private; uint32_t ch_ctl = output_reg + 0x10; uint32_t ch_data = ch_ctl + 4; @@ -253,7 +248,7 @@ intel_dp_aux_ch(struct intel_encoder *intel_encoder, * and would like to run at 2MHz. So, take the * hrawclk value and divide by 2 and use that */ - if (IS_eDP(intel_encoder)) { + if (IS_eDP(intel_dp)) { if (IS_GEN6(dev)) aux_clock_divider = 200; /* SNB eDP input clock at 400Mhz */ else @@ -344,7 +339,7 @@ intel_dp_aux_ch(struct intel_encoder *intel_encoder, /* Write data to the aux channel in native mode */ static int -intel_dp_aux_native_write(struct intel_encoder *intel_encoder, +intel_dp_aux_native_write(struct intel_dp *intel_dp, uint16_t address, uint8_t *send, int send_bytes) { int ret; @@ -361,7 +356,7 @@ intel_dp_aux_native_write(struct intel_encoder *intel_encoder, memcpy(&msg[4], send, send_bytes); msg_bytes = send_bytes + 4; for (;;) { - ret = intel_dp_aux_ch(intel_encoder, msg, msg_bytes, &ack, 1); + ret = intel_dp_aux_ch(intel_dp, msg, msg_bytes, &ack, 1); if (ret < 0) return ret; if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) @@ -376,15 +371,15 @@ intel_dp_aux_native_write(struct intel_encoder *intel_encoder, /* Write a single byte to the aux channel in native mode */ static int -intel_dp_aux_native_write_1(struct intel_encoder *intel_encoder, +intel_dp_aux_native_write_1(struct intel_dp *intel_dp, uint16_t address, uint8_t byte) { - return intel_dp_aux_native_write(intel_encoder, address, &byte, 1); + return intel_dp_aux_native_write(intel_dp, address, &byte, 1); } /* read bytes from a native aux channel */ static int -intel_dp_aux_native_read(struct intel_encoder *intel_encoder, +intel_dp_aux_native_read(struct intel_dp *intel_dp, uint16_t address, uint8_t *recv, int recv_bytes) { uint8_t msg[4]; @@ -403,7 +398,7 @@ intel_dp_aux_native_read(struct intel_encoder *intel_encoder, reply_bytes = recv_bytes + 1; for (;;) { - ret = intel_dp_aux_ch(intel_encoder, msg, msg_bytes, + ret = intel_dp_aux_ch(intel_dp, msg, msg_bytes, reply, reply_bytes); if (ret == 0) return -EPROTO; @@ -426,10 +421,9 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, uint8_t write_byte, uint8_t *read_byte) { struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; - struct intel_dp_priv *dp_priv = container_of(adapter, - struct intel_dp_priv, - adapter); - struct intel_encoder *intel_encoder = dp_priv->intel_encoder; + struct intel_dp *intel_dp = container_of(adapter, + struct intel_dp, + adapter); uint16_t address = algo_data->address; uint8_t msg[5]; uint8_t reply[2]; @@ -468,7 +462,7 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, } for (;;) { - ret = intel_dp_aux_ch(intel_encoder, + ret = intel_dp_aux_ch(intel_dp, msg, msg_bytes, reply, reply_bytes); if (ret < 0) { @@ -496,41 +490,38 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, } static int -intel_dp_i2c_init(struct intel_encoder *intel_encoder, +intel_dp_i2c_init(struct intel_dp *intel_dp, struct intel_connector *intel_connector, const char *name) { - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; - DRM_DEBUG_KMS("i2c_init %s\n", name); - dp_priv->algo.running = false; - dp_priv->algo.address = 0; - dp_priv->algo.aux_ch = intel_dp_i2c_aux_ch; - - memset(&dp_priv->adapter, '\0', sizeof (dp_priv->adapter)); - dp_priv->adapter.owner = THIS_MODULE; - dp_priv->adapter.class = I2C_CLASS_DDC; - strncpy (dp_priv->adapter.name, name, sizeof(dp_priv->adapter.name) - 1); - dp_priv->adapter.name[sizeof(dp_priv->adapter.name) - 1] = '\0'; - dp_priv->adapter.algo_data = &dp_priv->algo; - dp_priv->adapter.dev.parent = &intel_connector->base.kdev; - - return i2c_dp_aux_add_bus(&dp_priv->adapter); + intel_dp->algo.running = false; + intel_dp->algo.address = 0; + intel_dp->algo.aux_ch = intel_dp_i2c_aux_ch; + + memset(&intel_dp->adapter, '\0', sizeof (intel_dp->adapter)); + intel_dp->adapter.owner = THIS_MODULE; + intel_dp->adapter.class = I2C_CLASS_DDC; + strncpy (intel_dp->adapter.name, name, sizeof(intel_dp->adapter.name) - 1); + intel_dp->adapter.name[sizeof(intel_dp->adapter.name) - 1] = '\0'; + intel_dp->adapter.algo_data = &intel_dp->algo; + intel_dp->adapter.dev.parent = &intel_connector->base.kdev; + + return i2c_dp_aux_add_bus(&intel_dp->adapter); } static bool intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); int lane_count, clock; - int max_lane_count = intel_dp_max_lane_count(intel_encoder); - int max_clock = intel_dp_max_link_bw(intel_encoder) == DP_LINK_BW_2_7 ? 1 : 0; + int max_lane_count = intel_dp_max_lane_count(intel_dp); + int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0; static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 }; - if ((IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) && + if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) && dev_priv->panel_fixed_mode) { struct drm_display_mode *fixed_mode = dev_priv->panel_fixed_mode; @@ -558,28 +549,28 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, for (clock = 0; clock <= max_clock; clock++) { int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count); - if (intel_dp_link_required(encoder->dev, intel_encoder, mode->clock) + if (intel_dp_link_required(encoder->dev, intel_dp, mode->clock) <= link_avail) { - dp_priv->link_bw = bws[clock]; - dp_priv->lane_count = lane_count; - adjusted_mode->clock = intel_dp_link_clock(dp_priv->link_bw); + intel_dp->link_bw = bws[clock]; + intel_dp->lane_count = lane_count; + adjusted_mode->clock = intel_dp_link_clock(intel_dp->link_bw); DRM_DEBUG_KMS("Display port link bw %02x lane " "count %d clock %d\n", - dp_priv->link_bw, dp_priv->lane_count, + intel_dp->link_bw, intel_dp->lane_count, adjusted_mode->clock); return true; } } } - if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) { + if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) { /* okay we failed just pick the highest */ - dp_priv->lane_count = max_lane_count; - dp_priv->link_bw = bws[max_clock]; - adjusted_mode->clock = intel_dp_link_clock(dp_priv->link_bw); + intel_dp->lane_count = max_lane_count; + intel_dp->link_bw = bws[max_clock]; + adjusted_mode->clock = intel_dp_link_clock(intel_dp->link_bw); DRM_DEBUG_KMS("Force picking display port link bw %02x lane " "count %d clock %d\n", - dp_priv->link_bw, dp_priv->lane_count, + intel_dp->link_bw, intel_dp->lane_count, adjusted_mode->clock); return true; } @@ -626,17 +617,14 @@ bool intel_pch_has_edp(struct drm_crtc *crtc) struct drm_encoder *encoder; list_for_each_entry(encoder, &mode_config->encoder_list, head) { - struct intel_encoder *intel_encoder; - struct intel_dp_priv *dp_priv; + struct intel_dp *intel_dp; - if (!encoder || encoder->crtc != crtc) + if (encoder->crtc != crtc) continue; - intel_encoder = enc_to_intel_encoder(encoder); - dp_priv = intel_encoder->dev_priv; - - if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) - return dp_priv->is_pch_edp; + intel_dp = enc_to_intel_dp(encoder); + if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT) + return intel_dp->is_pch_edp; } return false; } @@ -657,18 +645,15 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, * Find the lane count in the intel_encoder private */ list_for_each_entry(encoder, &mode_config->encoder_list, head) { - struct intel_encoder *intel_encoder; - struct intel_dp_priv *dp_priv; + struct intel_dp *intel_dp; if (encoder->crtc != crtc) continue; - intel_encoder = enc_to_intel_encoder(encoder); - dp_priv = intel_encoder->dev_priv; - - if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) { - lane_count = dp_priv->lane_count; - if (IS_PCH_eDP(dp_priv)) + intel_dp = enc_to_intel_dp(encoder); + if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT) { + lane_count = intel_dp->lane_count; + if (IS_PCH_eDP(intel_dp)) bpp = dev_priv->edp_bpp; break; } @@ -724,61 +709,60 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; - struct drm_crtc *crtc = intel_encoder->enc.crtc; + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct drm_crtc *crtc = intel_dp->base.enc.crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - dp_priv->DP = (DP_VOLTAGE_0_4 | + intel_dp->DP = (DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0); if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) - dp_priv->DP |= DP_SYNC_HS_HIGH; + intel_dp->DP |= DP_SYNC_HS_HIGH; if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) - dp_priv->DP |= DP_SYNC_VS_HIGH; + intel_dp->DP |= DP_SYNC_VS_HIGH; - if (HAS_PCH_CPT(dev) && !IS_eDP(intel_encoder)) - dp_priv->DP |= DP_LINK_TRAIN_OFF_CPT; + if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp)) + intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT; else - dp_priv->DP |= DP_LINK_TRAIN_OFF; + intel_dp->DP |= DP_LINK_TRAIN_OFF; - switch (dp_priv->lane_count) { + switch (intel_dp->lane_count) { case 1: - dp_priv->DP |= DP_PORT_WIDTH_1; + intel_dp->DP |= DP_PORT_WIDTH_1; break; case 2: - dp_priv->DP |= DP_PORT_WIDTH_2; + intel_dp->DP |= DP_PORT_WIDTH_2; break; case 4: - dp_priv->DP |= DP_PORT_WIDTH_4; + intel_dp->DP |= DP_PORT_WIDTH_4; break; } - if (dp_priv->has_audio) - dp_priv->DP |= DP_AUDIO_OUTPUT_ENABLE; + if (intel_dp->has_audio) + intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE; - memset(dp_priv->link_configuration, 0, DP_LINK_CONFIGURATION_SIZE); - dp_priv->link_configuration[0] = dp_priv->link_bw; - dp_priv->link_configuration[1] = dp_priv->lane_count; + memset(intel_dp->link_configuration, 0, DP_LINK_CONFIGURATION_SIZE); + intel_dp->link_configuration[0] = intel_dp->link_bw; + intel_dp->link_configuration[1] = intel_dp->lane_count; /* * Check for DPCD version > 1.1 and enhanced framing support */ - if (dp_priv->dpcd[0] >= 0x11 && (dp_priv->dpcd[2] & DP_ENHANCED_FRAME_CAP)) { - dp_priv->link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; - dp_priv->DP |= DP_ENHANCED_FRAMING; + if (intel_dp->dpcd[0] >= 0x11 && (intel_dp->dpcd[2] & DP_ENHANCED_FRAME_CAP)) { + intel_dp->link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; + intel_dp->DP |= DP_ENHANCED_FRAMING; } /* CPT DP's pipe select is decided in TRANS_DP_CTL */ if (intel_crtc->pipe == 1 && !HAS_PCH_CPT(dev)) - dp_priv->DP |= DP_PIPEB_SELECT; + intel_dp->DP |= DP_PIPEB_SELECT; - if (IS_eDP(intel_encoder)) { + if (IS_eDP(intel_dp)) { /* don't miss out required setting for eDP */ - dp_priv->DP |= DP_PLL_ENABLE; + intel_dp->DP |= DP_PLL_ENABLE; if (adjusted_mode->clock < 200000) - dp_priv->DP |= DP_PLL_FREQ_160MHZ; + intel_dp->DP |= DP_PLL_FREQ_160MHZ; else - dp_priv->DP |= DP_PLL_FREQ_270MHZ; + intel_dp->DP |= DP_PLL_FREQ_270MHZ; } } @@ -852,30 +836,29 @@ static void ironlake_edp_backlight_off (struct drm_device *dev) static void intel_dp_dpms(struct drm_encoder *encoder, int mode) { - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t dp_reg = I915_READ(dp_priv->output_reg); + uint32_t dp_reg = I915_READ(intel_dp->output_reg); if (mode != DRM_MODE_DPMS_ON) { if (dp_reg & DP_PORT_EN) { - intel_dp_link_down(intel_encoder, dp_priv->DP); - if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) { + intel_dp_link_down(intel_dp); + if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) { ironlake_edp_backlight_off(dev); ironlake_edp_panel_off(dev); } } } else { if (!(dp_reg & DP_PORT_EN)) { - intel_dp_link_train(intel_encoder, dp_priv->DP, dp_priv->link_configuration); - if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) { + intel_dp_link_train(intel_dp); + if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) { ironlake_edp_panel_on(dev); ironlake_edp_backlight_on(dev); } } } - dp_priv->dpms_mode = mode; + intel_dp->dpms_mode = mode; } /* @@ -883,12 +866,12 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) * link status information */ static bool -intel_dp_get_link_status(struct intel_encoder *intel_encoder, +intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE]) { int ret; - ret = intel_dp_aux_native_read(intel_encoder, + ret = intel_dp_aux_native_read(intel_dp, DP_LANE0_1_STATUS, link_status, DP_LINK_STATUS_SIZE); if (ret != DP_LINK_STATUS_SIZE) @@ -965,7 +948,7 @@ intel_dp_pre_emphasis_max(uint8_t voltage_swing) } static void -intel_get_adjust_train(struct intel_encoder *intel_encoder, +intel_get_adjust_train(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count, uint8_t train_set[4]) @@ -1101,27 +1084,26 @@ intel_channel_eq_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count) } static bool -intel_dp_set_link_train(struct intel_encoder *intel_encoder, +intel_dp_set_link_train(struct intel_dp *intel_dp, uint32_t dp_reg_value, uint8_t dp_train_pat, uint8_t train_set[4], bool first) { - struct drm_device *dev = intel_encoder->enc.dev; + struct drm_device *dev = intel_dp->base.enc.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; int ret; - I915_WRITE(dp_priv->output_reg, dp_reg_value); - POSTING_READ(dp_priv->output_reg); + I915_WRITE(intel_dp->output_reg, dp_reg_value); + POSTING_READ(intel_dp->output_reg); if (first) intel_wait_for_vblank(dev); - intel_dp_aux_native_write_1(intel_encoder, + intel_dp_aux_native_write_1(intel_dp, DP_TRAINING_PATTERN_SET, dp_train_pat); - ret = intel_dp_aux_native_write(intel_encoder, + ret = intel_dp_aux_native_write(intel_dp, DP_TRAINING_LANE0_SET, train_set, 4); if (ret != 4) return false; @@ -1130,12 +1112,10 @@ intel_dp_set_link_train(struct intel_encoder *intel_encoder, } static void -intel_dp_link_train(struct intel_encoder *intel_encoder, uint32_t DP, - uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE]) +intel_dp_link_train(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_encoder->enc.dev; + struct drm_device *dev = intel_dp->base.enc.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; uint8_t train_set[4]; uint8_t link_status[DP_LINK_STATUS_SIZE]; int i; @@ -1145,13 +1125,15 @@ intel_dp_link_train(struct intel_encoder *intel_encoder, uint32_t DP, bool first = true; int tries; u32 reg; + uint32_t DP = intel_dp->DP; /* Write the link configuration data */ - intel_dp_aux_native_write(intel_encoder, DP_LINK_BW_SET, - link_configuration, DP_LINK_CONFIGURATION_SIZE); + intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET, + intel_dp->link_configuration, + DP_LINK_CONFIGURATION_SIZE); DP |= DP_PORT_EN; - if (HAS_PCH_CPT(dev) && !IS_eDP(intel_encoder)) + if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp)) DP &= ~DP_LINK_TRAIN_MASK_CPT; else DP &= ~DP_LINK_TRAIN_MASK; @@ -1162,39 +1144,39 @@ intel_dp_link_train(struct intel_encoder *intel_encoder, uint32_t DP, for (;;) { /* Use train_set[0] to set the voltage and pre emphasis values */ uint32_t signal_levels; - if (IS_GEN6(dev) && IS_eDP(intel_encoder)) { + if (IS_GEN6(dev) && IS_eDP(intel_dp)) { signal_levels = intel_gen6_edp_signal_levels(train_set[0]); DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels; } else { - signal_levels = intel_dp_signal_levels(train_set[0], dp_priv->lane_count); + signal_levels = intel_dp_signal_levels(train_set[0], intel_dp->lane_count); DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels; } - if (HAS_PCH_CPT(dev) && !IS_eDP(intel_encoder)) + if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp)) reg = DP | DP_LINK_TRAIN_PAT_1_CPT; else reg = DP | DP_LINK_TRAIN_PAT_1; - if (!intel_dp_set_link_train(intel_encoder, reg, + if (!intel_dp_set_link_train(intel_dp, reg, DP_TRAINING_PATTERN_1, train_set, first)) break; first = false; /* Set training pattern 1 */ udelay(100); - if (!intel_dp_get_link_status(intel_encoder, link_status)) + if (!intel_dp_get_link_status(intel_dp, link_status)) break; - if (intel_clock_recovery_ok(link_status, dp_priv->lane_count)) { + if (intel_clock_recovery_ok(link_status, intel_dp->lane_count)) { clock_recovery = true; break; } /* Check to see if we've tried the max voltage */ - for (i = 0; i < dp_priv->lane_count; i++) + for (i = 0; i < intel_dp->lane_count; i++) if ((train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0) break; - if (i == dp_priv->lane_count) + if (i == intel_dp->lane_count) break; /* Check to see if we've tried the same voltage 5 times */ @@ -1207,7 +1189,7 @@ intel_dp_link_train(struct intel_encoder *intel_encoder, uint32_t DP, voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK; /* Compute new train_set as requested by target */ - intel_get_adjust_train(intel_encoder, link_status, dp_priv->lane_count, train_set); + intel_get_adjust_train(intel_dp, link_status, intel_dp->lane_count, train_set); } /* channel equalization */ @@ -1217,30 +1199,30 @@ intel_dp_link_train(struct intel_encoder *intel_encoder, uint32_t DP, /* Use train_set[0] to set the voltage and pre emphasis values */ uint32_t signal_levels; - if (IS_GEN6(dev) && IS_eDP(intel_encoder)) { + if (IS_GEN6(dev) && IS_eDP(intel_dp)) { signal_levels = intel_gen6_edp_signal_levels(train_set[0]); DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels; } else { - signal_levels = intel_dp_signal_levels(train_set[0], dp_priv->lane_count); + signal_levels = intel_dp_signal_levels(train_set[0], intel_dp->lane_count); DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels; } - if (HAS_PCH_CPT(dev) && !IS_eDP(intel_encoder)) + if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp)) reg = DP | DP_LINK_TRAIN_PAT_2_CPT; else reg = DP | DP_LINK_TRAIN_PAT_2; /* channel eq pattern */ - if (!intel_dp_set_link_train(intel_encoder, reg, + if (!intel_dp_set_link_train(intel_dp, reg, DP_TRAINING_PATTERN_2, train_set, false)) break; udelay(400); - if (!intel_dp_get_link_status(intel_encoder, link_status)) + if (!intel_dp_get_link_status(intel_dp, link_status)) break; - if (intel_channel_eq_ok(link_status, dp_priv->lane_count)) { + if (intel_channel_eq_ok(link_status, intel_dp->lane_count)) { channel_eq = true; break; } @@ -1250,53 +1232,53 @@ intel_dp_link_train(struct intel_encoder *intel_encoder, uint32_t DP, break; /* Compute new train_set as requested by target */ - intel_get_adjust_train(intel_encoder, link_status, dp_priv->lane_count, train_set); + intel_get_adjust_train(intel_dp, link_status, intel_dp->lane_count, train_set); ++tries; } - if (HAS_PCH_CPT(dev) && !IS_eDP(intel_encoder)) + if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp)) reg = DP | DP_LINK_TRAIN_OFF_CPT; else reg = DP | DP_LINK_TRAIN_OFF; - I915_WRITE(dp_priv->output_reg, reg); - POSTING_READ(dp_priv->output_reg); - intel_dp_aux_native_write_1(intel_encoder, + I915_WRITE(intel_dp->output_reg, reg); + POSTING_READ(intel_dp->output_reg); + intel_dp_aux_native_write_1(intel_dp, DP_TRAINING_PATTERN_SET, DP_TRAINING_PATTERN_DISABLE); } static void -intel_dp_link_down(struct intel_encoder *intel_encoder, uint32_t DP) +intel_dp_link_down(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_encoder->enc.dev; + struct drm_device *dev = intel_dp->base.enc.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; + uint32_t DP = intel_dp->DP; DRM_DEBUG_KMS("\n"); - if (IS_eDP(intel_encoder)) { + if (IS_eDP(intel_dp)) { DP &= ~DP_PLL_ENABLE; - I915_WRITE(dp_priv->output_reg, DP); - POSTING_READ(dp_priv->output_reg); + I915_WRITE(intel_dp->output_reg, DP); + POSTING_READ(intel_dp->output_reg); udelay(100); } - if (HAS_PCH_CPT(dev) && !IS_eDP(intel_encoder)) { + if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp)) { DP &= ~DP_LINK_TRAIN_MASK_CPT; - I915_WRITE(dp_priv->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT); - POSTING_READ(dp_priv->output_reg); + I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT); + POSTING_READ(intel_dp->output_reg); } else { DP &= ~DP_LINK_TRAIN_MASK; - I915_WRITE(dp_priv->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE); - POSTING_READ(dp_priv->output_reg); + I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE); + POSTING_READ(intel_dp->output_reg); } udelay(17000); - if (IS_eDP(intel_encoder)) + if (IS_eDP(intel_dp)) DP |= DP_LINK_TRAIN_OFF; - I915_WRITE(dp_priv->output_reg, DP & ~DP_PORT_EN); - POSTING_READ(dp_priv->output_reg); + I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN); + POSTING_READ(intel_dp->output_reg); } /* @@ -1309,41 +1291,39 @@ intel_dp_link_down(struct intel_encoder *intel_encoder, uint32_t DP) */ static void -intel_dp_check_link_status(struct intel_encoder *intel_encoder) +intel_dp_check_link_status(struct intel_dp *intel_dp) { - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; uint8_t link_status[DP_LINK_STATUS_SIZE]; - if (!intel_encoder->enc.crtc) + if (!intel_dp->base.enc.crtc) return; - if (!intel_dp_get_link_status(intel_encoder, link_status)) { - intel_dp_link_down(intel_encoder, dp_priv->DP); + if (!intel_dp_get_link_status(intel_dp, link_status)) { + intel_dp_link_down(intel_dp); return; } - if (!intel_channel_eq_ok(link_status, dp_priv->lane_count)) - intel_dp_link_train(intel_encoder, dp_priv->DP, dp_priv->link_configuration); + if (!intel_channel_eq_ok(link_status, intel_dp->lane_count)) + intel_dp_link_train(intel_dp); } static enum drm_connector_status ironlake_dp_detect(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); enum drm_connector_status status; status = connector_status_disconnected; - if (intel_dp_aux_native_read(intel_encoder, - 0x000, dp_priv->dpcd, - sizeof (dp_priv->dpcd)) == sizeof (dp_priv->dpcd)) + if (intel_dp_aux_native_read(intel_dp, + 0x000, intel_dp->dpcd, + sizeof (intel_dp->dpcd)) == sizeof (intel_dp->dpcd)) { - if (dp_priv->dpcd[0] != 0) + if (intel_dp->dpcd[0] != 0) status = connector_status_connected; } - DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx\n", dp_priv->dpcd[0], - dp_priv->dpcd[1], dp_priv->dpcd[2], dp_priv->dpcd[3]); + DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx\n", intel_dp->dpcd[0], + intel_dp->dpcd[1], intel_dp->dpcd[2], intel_dp->dpcd[3]); return status; } @@ -1357,19 +1337,18 @@ static enum drm_connector_status intel_dp_detect(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct drm_device *dev = intel_encoder->enc.dev; + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct drm_device *dev = intel_dp->base.enc.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; uint32_t temp, bit; enum drm_connector_status status; - dp_priv->has_audio = false; + intel_dp->has_audio = false; if (HAS_PCH_SPLIT(dev)) return ironlake_dp_detect(connector); - switch (dp_priv->output_reg) { + switch (intel_dp->output_reg) { case DP_B: bit = DPB_HOTPLUG_INT_STATUS; break; @@ -1389,11 +1368,11 @@ intel_dp_detect(struct drm_connector *connector) return connector_status_disconnected; status = connector_status_disconnected; - if (intel_dp_aux_native_read(intel_encoder, - 0x000, dp_priv->dpcd, - sizeof (dp_priv->dpcd)) == sizeof (dp_priv->dpcd)) + if (intel_dp_aux_native_read(intel_dp, + 0x000, intel_dp->dpcd, + sizeof (intel_dp->dpcd)) == sizeof (intel_dp->dpcd)) { - if (dp_priv->dpcd[0] != 0) + if (intel_dp->dpcd[0] != 0) status = connector_status_connected; } return status; @@ -1402,18 +1381,17 @@ intel_dp_detect(struct drm_connector *connector) static int intel_dp_get_modes(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct drm_device *dev = intel_encoder->enc.dev; + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct drm_device *dev = intel_dp->base.enc.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; int ret; /* We should parse the EDID data and find out if it has an audio sink */ - ret = intel_ddc_get_modes(connector, intel_encoder->ddc_bus); + ret = intel_ddc_get_modes(connector, intel_dp->base.ddc_bus); if (ret) { - if ((IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) && + if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) && !dev_priv->panel_fixed_mode) { struct drm_display_mode *newmode; list_for_each_entry(newmode, &connector->probed_modes, @@ -1430,7 +1408,7 @@ static int intel_dp_get_modes(struct drm_connector *connector) } /* if eDP has no EDID, try to use fixed panel mode from VBT */ - if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) { + if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) { if (dev_priv->panel_fixed_mode != NULL) { struct drm_display_mode *mode; mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode); @@ -1470,27 +1448,17 @@ static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = .best_encoder = intel_attached_encoder, }; -static void intel_dp_enc_destroy(struct drm_encoder *encoder) -{ - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - - if (intel_encoder->i2c_bus) - intel_i2c_destroy(intel_encoder->i2c_bus); - drm_encoder_cleanup(encoder); - kfree(intel_encoder); -} - static const struct drm_encoder_funcs intel_dp_enc_funcs = { - .destroy = intel_dp_enc_destroy, + .destroy = intel_encoder_destroy, }; void intel_dp_hot_plug(struct intel_encoder *intel_encoder) { - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; + struct intel_dp *intel_dp = container_of(intel_encoder, struct intel_dp, base); - if (dp_priv->dpms_mode == DRM_MODE_DPMS_ON) - intel_dp_check_link_status(intel_encoder); + if (intel_dp->dpms_mode == DRM_MODE_DPMS_ON) + intel_dp_check_link_status(intel_dp); } /* Return which DP Port should be selected for Transcoder DP control */ @@ -1500,18 +1468,18 @@ intel_trans_dp_port_sel (struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct drm_mode_config *mode_config = &dev->mode_config; struct drm_encoder *encoder; - struct intel_encoder *intel_encoder = NULL; list_for_each_entry(encoder, &mode_config->encoder_list, head) { + struct intel_dp *intel_dp; + if (encoder->crtc != crtc) continue; - intel_encoder = enc_to_intel_encoder(encoder); - if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) { - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; - return dp_priv->output_reg; - } + intel_dp = enc_to_intel_dp(encoder); + if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT) + return intel_dp->output_reg; } + return -1; } @@ -1540,30 +1508,28 @@ intel_dp_init(struct drm_device *dev, int output_reg) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_connector *connector; + struct intel_dp *intel_dp; struct intel_encoder *intel_encoder; struct intel_connector *intel_connector; - struct intel_dp_priv *dp_priv; const char *name = NULL; int type; - intel_encoder = kcalloc(sizeof(struct intel_encoder) + - sizeof(struct intel_dp_priv), 1, GFP_KERNEL); - if (!intel_encoder) + intel_dp = kzalloc(sizeof(struct intel_dp), GFP_KERNEL); + if (!intel_dp) return; intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); if (!intel_connector) { - kfree(intel_encoder); + kfree(intel_dp); return; } + intel_encoder = &intel_dp->base; - dp_priv = (struct intel_dp_priv *)(intel_encoder + 1); - - if (HAS_PCH_SPLIT(dev) && (output_reg == PCH_DP_D)) + if (HAS_PCH_SPLIT(dev) && output_reg == PCH_DP_D) if (intel_dpd_is_edp(dev)) - dp_priv->is_pch_edp = true; + intel_dp->is_pch_edp = true; - if (output_reg == DP_A || IS_PCH_eDP(dp_priv)) { + if (output_reg == DP_A || IS_PCH_eDP(intel_dp)) { type = DRM_MODE_CONNECTOR_eDP; intel_encoder->type = INTEL_OUTPUT_EDP; } else { @@ -1584,18 +1550,16 @@ intel_dp_init(struct drm_device *dev, int output_reg) else if (output_reg == DP_D || output_reg == PCH_DP_D) intel_encoder->clone_mask = (1 << INTEL_DP_D_CLONE_BIT); - if (IS_eDP(intel_encoder)) + if (IS_eDP(intel_dp)) intel_encoder->clone_mask = (1 << INTEL_EDP_CLONE_BIT); intel_encoder->crtc_mask = (1 << 0) | (1 << 1); connector->interlace_allowed = true; connector->doublescan_allowed = 0; - dp_priv->intel_encoder = intel_encoder; - dp_priv->output_reg = output_reg; - dp_priv->has_audio = false; - dp_priv->dpms_mode = DRM_MODE_DPMS_ON; - intel_encoder->dev_priv = dp_priv; + intel_dp->output_reg = output_reg; + intel_dp->has_audio = false; + intel_dp->dpms_mode = DRM_MODE_DPMS_ON; drm_encoder_init(dev, &intel_encoder->enc, &intel_dp_enc_funcs, DRM_MODE_ENCODER_TMDS); @@ -1630,12 +1594,12 @@ intel_dp_init(struct drm_device *dev, int output_reg) break; } - intel_dp_i2c_init(intel_encoder, intel_connector, name); + intel_dp_i2c_init(intel_dp, intel_connector, name); - intel_encoder->ddc_bus = &dp_priv->adapter; + intel_encoder->ddc_bus = &intel_dp->adapter; intel_encoder->hot_plug = intel_dp_hot_plug; - if (output_reg == DP_A || IS_PCH_eDP(dp_priv)) { + if (output_reg == DP_A || IS_PCH_eDP(intel_dp)) { /* initialize panel mode from VBT if available for eDP */ if (dev_priv->lfp_lvds_vbt_mode) { dev_priv->panel_fixed_mode = diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index b219014..520b22c 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -102,7 +102,6 @@ struct intel_encoder { struct i2c_adapter *ddc_bus; bool load_detect_temp; bool needs_tv_clock; - void *dev_priv; void (*hot_plug)(struct intel_encoder *); int crtc_mask; int clone_mask; @@ -192,6 +191,7 @@ extern int intel_panel_fitter_pipe (struct drm_device *dev); extern void intel_crtc_load_lut(struct drm_crtc *crtc); extern void intel_encoder_prepare (struct drm_encoder *encoder); extern void intel_encoder_commit (struct drm_encoder *encoder); +extern void intel_encoder_destroy(struct drm_encoder *encoder); extern struct drm_encoder *intel_attached_encoder(struct drm_connector *connector); diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 227feca..a399f4b 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -38,7 +38,7 @@ #define CH7xxx_ADDR 0x76 #define TFP410_ADDR 0x38 -static struct intel_dvo_device intel_dvo_devices[] = { +static const struct intel_dvo_device intel_dvo_devices[] = { { .type = INTEL_DVO_CHIP_TMDS, .name = "sil164", @@ -77,20 +77,33 @@ static struct intel_dvo_device intel_dvo_devices[] = { } }; +struct intel_dvo { + struct intel_encoder base; + + struct intel_dvo_device dev; + + struct drm_display_mode *panel_fixed_mode; + bool panel_wants_dither; +}; + +static struct intel_dvo *enc_to_intel_dvo(struct drm_encoder *encoder) +{ + return container_of(enc_to_intel_encoder(encoder), struct intel_dvo, base); +} + static void intel_dvo_dpms(struct drm_encoder *encoder, int mode) { struct drm_i915_private *dev_priv = encoder->dev->dev_private; - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_dvo_device *dvo = intel_encoder->dev_priv; - u32 dvo_reg = dvo->dvo_reg; + struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); + u32 dvo_reg = intel_dvo->dev.dvo_reg; u32 temp = I915_READ(dvo_reg); if (mode == DRM_MODE_DPMS_ON) { I915_WRITE(dvo_reg, temp | DVO_ENABLE); I915_READ(dvo_reg); - dvo->dev_ops->dpms(dvo, mode); + intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, mode); } else { - dvo->dev_ops->dpms(dvo, mode); + intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, mode); I915_WRITE(dvo_reg, temp & ~DVO_ENABLE); I915_READ(dvo_reg); } @@ -100,38 +113,36 @@ static int intel_dvo_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_dvo_device *dvo = intel_encoder->dev_priv; + struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; /* XXX: Validate clock range */ - if (dvo->panel_fixed_mode) { - if (mode->hdisplay > dvo->panel_fixed_mode->hdisplay) + if (intel_dvo->panel_fixed_mode) { + if (mode->hdisplay > intel_dvo->panel_fixed_mode->hdisplay) return MODE_PANEL; - if (mode->vdisplay > dvo->panel_fixed_mode->vdisplay) + if (mode->vdisplay > intel_dvo->panel_fixed_mode->vdisplay) return MODE_PANEL; } - return dvo->dev_ops->mode_valid(dvo, mode); + return intel_dvo->dev.dev_ops->mode_valid(&intel_dvo->dev, mode); } static bool intel_dvo_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_dvo_device *dvo = intel_encoder->dev_priv; + struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); /* If we have timings from the BIOS for the panel, put them in * to the adjusted mode. The CRTC will be set up for this mode, * with the panel scaling set up to source from the H/VDisplay * of the original mode. */ - if (dvo->panel_fixed_mode != NULL) { -#define C(x) adjusted_mode->x = dvo->panel_fixed_mode->x + if (intel_dvo->panel_fixed_mode != NULL) { +#define C(x) adjusted_mode->x = intel_dvo->panel_fixed_mode->x C(hdisplay); C(hsync_start); C(hsync_end); @@ -145,8 +156,8 @@ static bool intel_dvo_mode_fixup(struct drm_encoder *encoder, #undef C } - if (dvo->dev_ops->mode_fixup) - return dvo->dev_ops->mode_fixup(dvo, mode, adjusted_mode); + if (intel_dvo->dev.dev_ops->mode_fixup) + return intel_dvo->dev.dev_ops->mode_fixup(&intel_dvo->dev, mode, adjusted_mode); return true; } @@ -158,11 +169,10 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder, struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_dvo_device *dvo = intel_encoder->dev_priv; + struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); int pipe = intel_crtc->pipe; u32 dvo_val; - u32 dvo_reg = dvo->dvo_reg, dvo_srcdim_reg; + u32 dvo_reg = intel_dvo->dev.dvo_reg, dvo_srcdim_reg; int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; switch (dvo_reg) { @@ -178,7 +188,7 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder, break; } - dvo->dev_ops->mode_set(dvo, mode, adjusted_mode); + intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev, mode, adjusted_mode); /* Save the data order, since I don't know what it should be set to. */ dvo_val = I915_READ(dvo_reg) & @@ -214,40 +224,38 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder, static enum drm_connector_status intel_dvo_detect(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_dvo_device *dvo = intel_encoder->dev_priv; + struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); - return dvo->dev_ops->detect(dvo); + return intel_dvo->dev.dev_ops->detect(&intel_dvo->dev); } static int intel_dvo_get_modes(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_dvo_device *dvo = intel_encoder->dev_priv; + struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); /* We should probably have an i2c driver get_modes function for those * devices which will have a fixed set of modes determined by the chip * (TV-out, for example), but for now with just TMDS and LVDS, * that's not the case. */ - intel_ddc_get_modes(connector, intel_encoder->ddc_bus); + intel_ddc_get_modes(connector, intel_dvo->base.ddc_bus); if (!list_empty(&connector->probed_modes)) return 1; - - if (dvo->panel_fixed_mode != NULL) { + if (intel_dvo->panel_fixed_mode != NULL) { struct drm_display_mode *mode; - mode = drm_mode_duplicate(connector->dev, dvo->panel_fixed_mode); + mode = drm_mode_duplicate(connector->dev, intel_dvo->panel_fixed_mode); if (mode) { drm_mode_probed_add(connector, mode); return 1; } } + return 0; } -static void intel_dvo_destroy (struct drm_connector *connector) +static void intel_dvo_destroy(struct drm_connector *connector) { drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); @@ -277,28 +285,20 @@ static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs static void intel_dvo_enc_destroy(struct drm_encoder *encoder) { - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_dvo_device *dvo = intel_encoder->dev_priv; - - if (dvo) { - if (dvo->dev_ops->destroy) - dvo->dev_ops->destroy(dvo); - if (dvo->panel_fixed_mode) - kfree(dvo->panel_fixed_mode); - } - if (intel_encoder->i2c_bus) - intel_i2c_destroy(intel_encoder->i2c_bus); - if (intel_encoder->ddc_bus) - intel_i2c_destroy(intel_encoder->ddc_bus); - drm_encoder_cleanup(encoder); - kfree(intel_encoder); + struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); + + if (intel_dvo->dev.dev_ops->destroy) + intel_dvo->dev.dev_ops->destroy(&intel_dvo->dev); + + kfree(intel_dvo->panel_fixed_mode); + + intel_encoder_destroy(encoder); } static const struct drm_encoder_funcs intel_dvo_enc_funcs = { .destroy = intel_dvo_enc_destroy, }; - /** * Attempts to get a fixed panel timing for LVDS (currently only the i830). * @@ -306,15 +306,13 @@ static const struct drm_encoder_funcs intel_dvo_enc_funcs = { * chip being on DVOB/C and having multiple pipes. */ static struct drm_display_mode * -intel_dvo_get_current_mode (struct drm_connector *connector) +intel_dvo_get_current_mode(struct drm_connector *connector) { struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_dvo_device *dvo = intel_encoder->dev_priv; - uint32_t dvo_reg = dvo->dvo_reg; - uint32_t dvo_val = I915_READ(dvo_reg); + struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); + uint32_t dvo_val = I915_READ(intel_dvo->dev.dvo_reg); struct drm_display_mode *mode = NULL; /* If the DVO port is active, that'll be the LVDS, so we can pull out @@ -327,7 +325,6 @@ intel_dvo_get_current_mode (struct drm_connector *connector) crtc = intel_get_crtc_from_pipe(dev, pipe); if (crtc) { mode = intel_crtc_mode_get(dev, crtc); - if (mode) { mode->type |= DRM_MODE_TYPE_PREFERRED; if (dvo_val & DVO_HSYNC_ACTIVE_HIGH) @@ -337,28 +334,32 @@ intel_dvo_get_current_mode (struct drm_connector *connector) } } } + return mode; } void intel_dvo_init(struct drm_device *dev) { struct intel_encoder *intel_encoder; + struct intel_dvo *intel_dvo; struct intel_connector *intel_connector; - struct intel_dvo_device *dvo; struct i2c_adapter *i2cbus = NULL; int ret = 0; int i; int encoder_type = DRM_MODE_ENCODER_NONE; - intel_encoder = kzalloc (sizeof(struct intel_encoder), GFP_KERNEL); - if (!intel_encoder) + + intel_dvo = kzalloc(sizeof(struct intel_dvo), GFP_KERNEL); + if (!intel_dvo) return; intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); if (!intel_connector) { - kfree(intel_encoder); + kfree(intel_dvo); return; } + intel_encoder = &intel_dvo->base; + /* Set up the DDC bus */ intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOD, "DVODDC_D"); if (!intel_encoder->ddc_bus) @@ -367,10 +368,9 @@ void intel_dvo_init(struct drm_device *dev) /* Now, try to find a controller */ for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) { struct drm_connector *connector = &intel_connector->base; + const struct intel_dvo_device *dvo = &intel_dvo_devices[i]; int gpio; - dvo = &intel_dvo_devices[i]; - /* Allow the I2C driver info to specify the GPIO to be used in * special cases, but otherwise default to what's defined * in the spec. @@ -393,11 +393,8 @@ void intel_dvo_init(struct drm_device *dev) continue; } - if (dvo->dev_ops!= NULL) - ret = dvo->dev_ops->init(dvo, i2cbus); - else - ret = false; - + intel_dvo->dev = *dvo; + ret = dvo->dev_ops->init(&intel_dvo->dev, i2cbus); if (!ret) continue; @@ -429,9 +426,6 @@ void intel_dvo_init(struct drm_device *dev) connector->interlace_allowed = false; connector->doublescan_allowed = false; - intel_encoder->dev_priv = dvo; - intel_encoder->i2c_bus = i2cbus; - drm_encoder_init(dev, &intel_encoder->enc, &intel_dvo_enc_funcs, encoder_type); drm_encoder_helper_add(&intel_encoder->enc, @@ -447,9 +441,9 @@ void intel_dvo_init(struct drm_device *dev) * headers, likely), so for now, just get the current * mode being output through DVO. */ - dvo->panel_fixed_mode = + intel_dvo->panel_fixed_mode = intel_dvo_get_current_mode(connector); - dvo->panel_wants_dither = true; + intel_dvo->panel_wants_dither = true; } drm_sysfs_connector_add(connector); @@ -461,6 +455,6 @@ void intel_dvo_init(struct drm_device *dev) if (i2cbus != NULL) intel_i2c_destroy(i2cbus); free_intel: - kfree(intel_encoder); + kfree(intel_dvo); kfree(intel_connector); } diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 197887e..ccd4c97 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -37,11 +37,17 @@ #include "i915_drm.h" #include "i915_drv.h" -struct intel_hdmi_priv { +struct intel_hdmi { + struct intel_encoder base; u32 sdvox_reg; bool has_hdmi_sink; }; +static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder) +{ + return container_of(enc_to_intel_encoder(encoder), struct intel_hdmi, base); +} + static void intel_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -50,8 +56,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = encoder->crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_hdmi_priv *hdmi_priv = intel_encoder->dev_priv; + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); u32 sdvox; sdvox = SDVO_ENCODING_HDMI | SDVO_BORDER_ENABLE; @@ -60,7 +65,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) sdvox |= SDVO_HSYNC_ACTIVE_HIGH; - if (hdmi_priv->has_hdmi_sink) { + if (intel_hdmi->has_hdmi_sink) { sdvox |= SDVO_AUDIO_ENABLE; if (HAS_PCH_CPT(dev)) sdvox |= HDMI_MODE_SELECT; @@ -73,26 +78,25 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, sdvox |= SDVO_PIPE_B_SELECT; } - I915_WRITE(hdmi_priv->sdvox_reg, sdvox); - POSTING_READ(hdmi_priv->sdvox_reg); + I915_WRITE(intel_hdmi->sdvox_reg, sdvox); + POSTING_READ(intel_hdmi->sdvox_reg); } static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_hdmi_priv *hdmi_priv = intel_encoder->dev_priv; + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); u32 temp; - temp = I915_READ(hdmi_priv->sdvox_reg); + temp = I915_READ(intel_hdmi->sdvox_reg); /* 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(hdmi_priv->sdvox_reg, temp & ~SDVO_ENABLE); - POSTING_READ(hdmi_priv->sdvox_reg); + I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE); + POSTING_READ(intel_hdmi->sdvox_reg); } if (mode != DRM_MODE_DPMS_ON) { @@ -101,15 +105,15 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) temp |= SDVO_ENABLE; } - I915_WRITE(hdmi_priv->sdvox_reg, temp); - POSTING_READ(hdmi_priv->sdvox_reg); + I915_WRITE(intel_hdmi->sdvox_reg, temp); + POSTING_READ(intel_hdmi->sdvox_reg); /* HW workaround, need to write this twice for issue that may result * in first write getting masked. */ if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(hdmi_priv->sdvox_reg, temp); - POSTING_READ(hdmi_priv->sdvox_reg); + I915_WRITE(intel_hdmi->sdvox_reg, temp); + POSTING_READ(intel_hdmi->sdvox_reg); } } @@ -138,19 +142,17 @@ static enum drm_connector_status intel_hdmi_detect(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_hdmi_priv *hdmi_priv = intel_encoder->dev_priv; + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); struct edid *edid = NULL; enum drm_connector_status status = connector_status_disconnected; - hdmi_priv->has_hdmi_sink = false; - edid = drm_get_edid(connector, - intel_encoder->ddc_bus); + intel_hdmi->has_hdmi_sink = false; + edid = drm_get_edid(connector, intel_hdmi->base.ddc_bus); if (edid) { if (edid->input & DRM_EDID_INPUT_DIGITAL) { status = connector_status_connected; - hdmi_priv->has_hdmi_sink = drm_detect_hdmi_monitor(edid); + intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid); } connector->display_info.raw_edid = NULL; kfree(edid); @@ -162,13 +164,13 @@ intel_hdmi_detect(struct drm_connector *connector) static int intel_hdmi_get_modes(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); /* We should parse the EDID data and find out if it's an HDMI sink so * we can send audio to it. */ - return intel_ddc_get_modes(connector, intel_encoder->ddc_bus); + return intel_ddc_get_modes(connector, intel_hdmi->base.ddc_bus); } static void intel_hdmi_destroy(struct drm_connector *connector) @@ -199,18 +201,8 @@ static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs .best_encoder = intel_attached_encoder, }; -static void intel_hdmi_enc_destroy(struct drm_encoder *encoder) -{ - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - - if (intel_encoder->i2c_bus) - intel_i2c_destroy(intel_encoder->i2c_bus); - drm_encoder_cleanup(encoder); - kfree(intel_encoder); -} - static const struct drm_encoder_funcs intel_hdmi_enc_funcs = { - .destroy = intel_hdmi_enc_destroy, + .destroy = intel_encoder_destroy, }; void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) @@ -219,21 +211,19 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) struct drm_connector *connector; struct intel_encoder *intel_encoder; struct intel_connector *intel_connector; - struct intel_hdmi_priv *hdmi_priv; + struct intel_hdmi *intel_hdmi; - intel_encoder = kcalloc(sizeof(struct intel_encoder) + - sizeof(struct intel_hdmi_priv), 1, GFP_KERNEL); - if (!intel_encoder) + intel_hdmi = kzalloc(sizeof(struct intel_hdmi), GFP_KERNEL); + if (!intel_hdmi) return; intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); if (!intel_connector) { - kfree(intel_encoder); + kfree(intel_hdmi); return; } - hdmi_priv = (struct intel_hdmi_priv *)(intel_encoder + 1); - + intel_encoder = &intel_hdmi->base; connector = &intel_connector->base; drm_connector_init(dev, connector, &intel_hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA); @@ -274,8 +264,7 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) if (!intel_encoder->ddc_bus) goto err_connector; - hdmi_priv->sdvox_reg = sdvox_reg; - intel_encoder->dev_priv = hdmi_priv; + intel_hdmi->sdvox_reg = sdvox_reg; drm_encoder_init(dev, &intel_encoder->enc, &intel_hdmi_enc_funcs, DRM_MODE_ENCODER_TMDS); @@ -298,7 +287,7 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) err_connector: drm_connector_cleanup(connector); - kfree(intel_encoder); + kfree(intel_hdmi); kfree(intel_connector); return; diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 0a2e600..312ac30 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -41,12 +41,18 @@ #include /* Private structure for the integrated LVDS support */ -struct intel_lvds_priv { +struct intel_lvds { + struct intel_encoder base; int fitting_mode; u32 pfit_control; u32 pfit_pgm_ratios; }; +static struct intel_lvds *enc_to_intel_lvds(struct drm_encoder *encoder) +{ + return container_of(enc_to_intel_encoder(encoder), struct intel_lvds, base); +} + /** * Sets the backlight level. * @@ -219,9 +225,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); + struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder); struct drm_encoder *tmp_encoder; - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_lvds_priv *lvds_priv = intel_encoder->dev_priv; u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; /* Should never happen!! */ @@ -293,7 +298,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, I915_WRITE(BCLRPAT_B, 0); } - switch (lvds_priv->fitting_mode) { + switch (intel_lvds->fitting_mode) { case DRM_MODE_SCALE_CENTER: /* * For centered modes, we have to calculate border widths & @@ -378,8 +383,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, } out: - lvds_priv->pfit_control = pfit_control; - lvds_priv->pfit_pgm_ratios = pfit_pgm_ratios; + intel_lvds->pfit_control = pfit_control; + intel_lvds->pfit_pgm_ratios = pfit_pgm_ratios; dev_priv->lvds_border_bits = border; /* @@ -427,8 +432,7 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder, { struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_lvds_priv *lvds_priv = intel_encoder->dev_priv; + struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder); /* * The LVDS pin pair will already have been turned on in the @@ -444,8 +448,8 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder, * screen. Should be enabled before the pipe is enabled, according to * register description and PRM. */ - I915_WRITE(PFIT_PGM_RATIOS, lvds_priv->pfit_pgm_ratios); - I915_WRITE(PFIT_CONTROL, lvds_priv->pfit_control); + I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios); + I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control); } /** @@ -600,18 +604,17 @@ static int intel_lvds_set_property(struct drm_connector *connector, connector->encoder) { struct drm_crtc *crtc = connector->encoder->crtc; struct drm_encoder *encoder = connector->encoder; - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_lvds_priv *lvds_priv = intel_encoder->dev_priv; + struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder); if (value == DRM_MODE_SCALE_NONE) { DRM_DEBUG_KMS("no scaling not supported\n"); return 0; } - if (lvds_priv->fitting_mode == value) { + if (intel_lvds->fitting_mode == value) { /* the LVDS scaling property is not changed */ return 0; } - lvds_priv->fitting_mode = value; + intel_lvds->fitting_mode = value; if (crtc && crtc->enabled) { /* * If the CRTC is enabled, the display will be changed @@ -647,19 +650,8 @@ static const struct drm_connector_funcs intel_lvds_connector_funcs = { .destroy = intel_lvds_destroy, }; - -static void intel_lvds_enc_destroy(struct drm_encoder *encoder) -{ - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - - if (intel_encoder->ddc_bus) - intel_i2c_destroy(intel_encoder->ddc_bus); - drm_encoder_cleanup(encoder); - kfree(intel_encoder); -} - static const struct drm_encoder_funcs intel_lvds_enc_funcs = { - .destroy = intel_lvds_enc_destroy, + .destroy = intel_encoder_destroy, }; static int __init intel_no_lvds_dmi_callback(const struct dmi_system_id *id) @@ -843,13 +835,13 @@ static int lvds_is_present_in_vbt(struct drm_device *dev) void intel_lvds_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_lvds *intel_lvds; struct intel_encoder *intel_encoder; struct intel_connector *intel_connector; struct drm_connector *connector; struct drm_encoder *encoder; struct drm_display_mode *scan; /* *modes, *bios_mode; */ struct drm_crtc *crtc; - struct intel_lvds_priv *lvds_priv; u32 lvds; int pipe, gpio = GPIOC; @@ -872,20 +864,20 @@ void intel_lvds_init(struct drm_device *dev) gpio = PCH_GPIOC; } - intel_encoder = kzalloc(sizeof(struct intel_encoder) + - sizeof(struct intel_lvds_priv), GFP_KERNEL); - if (!intel_encoder) { + intel_lvds = kzalloc(sizeof(struct intel_lvds), GFP_KERNEL); + if (!intel_lvds) { return; } intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); if (!intel_connector) { - kfree(intel_encoder); + kfree(intel_lvds); return; } - connector = &intel_connector->base; + intel_encoder = &intel_lvds->base; encoder = &intel_encoder->enc; + connector = &intel_connector->base; drm_connector_init(dev, &intel_connector->base, &intel_lvds_connector_funcs, DRM_MODE_CONNECTOR_LVDS); @@ -905,8 +897,6 @@ void intel_lvds_init(struct drm_device *dev) connector->interlace_allowed = false; connector->doublescan_allowed = false; - lvds_priv = (struct intel_lvds_priv *)(intel_encoder + 1); - intel_encoder->dev_priv = lvds_priv; /* create the scaling mode property */ drm_mode_create_scaling_mode_property(dev); /* @@ -916,7 +906,7 @@ void intel_lvds_init(struct drm_device *dev) drm_connector_attach_property(&intel_connector->base, dev->mode_config.scaling_mode_property, DRM_MODE_SCALE_ASPECT); - lvds_priv->fitting_mode = DRM_MODE_SCALE_ASPECT; + intel_lvds->fitting_mode = DRM_MODE_SCALE_ASPECT; /* * LVDS discovery: * 1) check for EDID on DDC @@ -1024,6 +1014,6 @@ failed: intel_i2c_destroy(intel_encoder->ddc_bus); drm_connector_cleanup(connector); drm_encoder_cleanup(encoder); - kfree(intel_encoder); + kfree(intel_lvds); kfree(intel_connector); } diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index d9d4d51..2fc9da4 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -31,8 +31,8 @@ #include "drmP.h" #include "drm.h" #include "drm_crtc.h" -#include "intel_drv.h" #include "drm_edid.h" +#include "intel_drv.h" #include "i915_drm.h" #include "i915_drv.h" #include "intel_sdvo_regs.h" @@ -61,7 +61,9 @@ static char *tv_format_names[] = { #define TV_FORMAT_NUM (sizeof(tv_format_names) / sizeof(*tv_format_names)) -struct intel_sdvo_priv { +struct intel_sdvo { + struct intel_encoder base; + u8 slave_addr; /* Register for the SDVO device: SDVOB or SDVOC */ @@ -173,9 +175,13 @@ struct intel_sdvo_connector { u32 cur_hue, max_hue; }; +static struct intel_sdvo *enc_to_intel_sdvo(struct drm_encoder *encoder) +{ + return container_of(enc_to_intel_encoder(encoder), struct intel_sdvo, base); +} + static bool -intel_sdvo_output_setup(struct intel_encoder *intel_encoder, - uint16_t flags); +intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags); static void intel_sdvo_tv_create_property(struct drm_connector *connector, int type); static void @@ -186,21 +192,20 @@ intel_sdvo_create_enhance_property(struct drm_connector *connector); * SDVOB and SDVOC to work around apparent hardware issues (according to * comments in the BIOS). */ -static void intel_sdvo_write_sdvox(struct intel_encoder *intel_encoder, u32 val) +static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val) { - struct drm_device *dev = intel_encoder->enc.dev; + struct drm_device *dev = intel_sdvo->base.enc.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; u32 bval = val, cval = val; int i; - if (sdvo_priv->sdvo_reg == PCH_SDVOB) { - I915_WRITE(sdvo_priv->sdvo_reg, val); - I915_READ(sdvo_priv->sdvo_reg); + if (intel_sdvo->sdvo_reg == PCH_SDVOB) { + I915_WRITE(intel_sdvo->sdvo_reg, val); + I915_READ(intel_sdvo->sdvo_reg); return; } - if (sdvo_priv->sdvo_reg == SDVOB) { + if (intel_sdvo->sdvo_reg == SDVOB) { cval = I915_READ(SDVOC); } else { bval = I915_READ(SDVOB); @@ -219,23 +224,22 @@ static void intel_sdvo_write_sdvox(struct intel_encoder *intel_encoder, u32 val) } } -static bool intel_sdvo_read_byte(struct intel_encoder *intel_encoder, u8 addr, +static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, u8 *ch) { - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; u8 out_buf[2]; u8 buf[2]; int ret; struct i2c_msg msgs[] = { { - .addr = sdvo_priv->slave_addr >> 1, + .addr = intel_sdvo->slave_addr >> 1, .flags = 0, .len = 1, .buf = out_buf, }, { - .addr = sdvo_priv->slave_addr >> 1, + .addr = intel_sdvo->slave_addr >> 1, .flags = I2C_M_RD, .len = 1, .buf = buf, @@ -245,7 +249,7 @@ static bool intel_sdvo_read_byte(struct intel_encoder *intel_encoder, u8 addr, out_buf[0] = addr; out_buf[1] = 0; - if ((ret = i2c_transfer(intel_encoder->i2c_bus, msgs, 2)) == 2) + if ((ret = i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 2)) == 2) { *ch = buf[0]; return true; @@ -255,14 +259,13 @@ static bool intel_sdvo_read_byte(struct intel_encoder *intel_encoder, u8 addr, return false; } -static bool intel_sdvo_write_byte(struct intel_encoder *intel_encoder, int addr, +static bool intel_sdvo_write_byte(struct intel_sdvo *intel_sdvo, int addr, u8 ch) { - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; u8 out_buf[2]; struct i2c_msg msgs[] = { { - .addr = sdvo_priv->slave_addr >> 1, + .addr = intel_sdvo->slave_addr >> 1, .flags = 0, .len = 2, .buf = out_buf, @@ -272,7 +275,7 @@ static bool intel_sdvo_write_byte(struct intel_encoder *intel_encoder, int addr, out_buf[0] = addr; out_buf[1] = ch; - if (i2c_transfer(intel_encoder->i2c_bus, msgs, 1) == 1) + if (i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 1) == 1) { return true; } @@ -377,17 +380,15 @@ static const struct _sdvo_cmd_name { }; #define IS_SDVOB(reg) (reg == SDVOB || reg == PCH_SDVOB) -#define SDVO_NAME(dev_priv) (IS_SDVOB((dev_priv)->sdvo_reg) ? "SDVOB" : "SDVOC") -#define SDVO_PRIV(encoder) ((struct intel_sdvo_priv *) (encoder)->dev_priv) +#define SDVO_NAME(svdo) (IS_SDVOB((svdo)->sdvo_reg) ? "SDVOB" : "SDVOC") -static void intel_sdvo_debug_write(struct intel_encoder *intel_encoder, u8 cmd, +static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd, void *args, int args_len) { - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; int i; DRM_DEBUG_KMS("%s: W: %02X ", - SDVO_NAME(sdvo_priv), cmd); + SDVO_NAME(intel_sdvo), cmd); for (i = 0; i < args_len; i++) DRM_LOG_KMS("%02X ", ((u8 *)args)[i]); for (; i < 8; i++) @@ -403,19 +404,19 @@ static void intel_sdvo_debug_write(struct intel_encoder *intel_encoder, u8 cmd, DRM_LOG_KMS("\n"); } -static void intel_sdvo_write_cmd(struct intel_encoder *intel_encoder, u8 cmd, +static void intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd, void *args, int args_len) { int i; - intel_sdvo_debug_write(intel_encoder, cmd, args, args_len); + intel_sdvo_debug_write(intel_sdvo, cmd, args, args_len); for (i = 0; i < args_len; i++) { - intel_sdvo_write_byte(intel_encoder, SDVO_I2C_ARG_0 - i, + intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_ARG_0 - i, ((u8*)args)[i]); } - intel_sdvo_write_byte(intel_encoder, SDVO_I2C_OPCODE, cmd); + intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_OPCODE, cmd); } static const char *cmd_status_names[] = { @@ -428,14 +429,13 @@ static const char *cmd_status_names[] = { "Scaling not supported" }; -static void intel_sdvo_debug_response(struct intel_encoder *intel_encoder, +static void intel_sdvo_debug_response(struct intel_sdvo *intel_sdvo, void *response, int response_len, u8 status) { - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; int i; - DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(sdvo_priv)); + DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(intel_sdvo)); for (i = 0; i < response_len; i++) DRM_LOG_KMS("%02X ", ((u8 *)response)[i]); for (; i < 8; i++) @@ -447,7 +447,7 @@ static void intel_sdvo_debug_response(struct intel_encoder *intel_encoder, DRM_LOG_KMS("\n"); } -static u8 intel_sdvo_read_response(struct intel_encoder *intel_encoder, +static u8 intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, void *response, int response_len) { int i; @@ -457,16 +457,16 @@ static u8 intel_sdvo_read_response(struct intel_encoder *intel_encoder, while (retry--) { /* Read the command response */ for (i = 0; i < response_len; i++) { - intel_sdvo_read_byte(intel_encoder, + intel_sdvo_read_byte(intel_sdvo, SDVO_I2C_RETURN_0 + i, &((u8 *)response)[i]); } /* read the return status */ - intel_sdvo_read_byte(intel_encoder, SDVO_I2C_CMD_STATUS, + intel_sdvo_read_byte(intel_sdvo, SDVO_I2C_CMD_STATUS, &status); - intel_sdvo_debug_response(intel_encoder, response, response_len, + intel_sdvo_debug_response(intel_sdvo, response, response_len, status); if (status != SDVO_CMD_STATUS_PENDING) return status; @@ -494,37 +494,36 @@ static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode) * another I2C transaction after issuing the DDC bus switch, it will be * switched to the internal SDVO register. */ -static void intel_sdvo_set_control_bus_switch(struct intel_encoder *intel_encoder, +static void intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo, u8 target) { - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; u8 out_buf[2], cmd_buf[2], ret_value[2], ret; struct i2c_msg msgs[] = { { - .addr = sdvo_priv->slave_addr >> 1, + .addr = intel_sdvo->slave_addr >> 1, .flags = 0, .len = 2, .buf = out_buf, }, /* the following two are to read the response */ { - .addr = sdvo_priv->slave_addr >> 1, + .addr = intel_sdvo->slave_addr >> 1, .flags = 0, .len = 1, .buf = cmd_buf, }, { - .addr = sdvo_priv->slave_addr >> 1, + .addr = intel_sdvo->slave_addr >> 1, .flags = I2C_M_RD, .len = 1, .buf = ret_value, }, }; - intel_sdvo_debug_write(intel_encoder, SDVO_CMD_SET_CONTROL_BUS_SWITCH, + intel_sdvo_debug_write(intel_sdvo, SDVO_CMD_SET_CONTROL_BUS_SWITCH, &target, 1); /* write the DDC switch command argument */ - intel_sdvo_write_byte(intel_encoder, SDVO_I2C_ARG_0, target); + intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_ARG_0, target); out_buf[0] = SDVO_I2C_OPCODE; out_buf[1] = SDVO_CMD_SET_CONTROL_BUS_SWITCH; @@ -533,7 +532,7 @@ static void intel_sdvo_set_control_bus_switch(struct intel_encoder *intel_encode ret_value[0] = 0; ret_value[1] = 0; - ret = i2c_transfer(intel_encoder->i2c_bus, msgs, 3); + ret = i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 3); if (ret != 3) { /* failure in I2C transfer */ DRM_DEBUG_KMS("I2c transfer returned %d\n", ret); @@ -547,7 +546,7 @@ static void intel_sdvo_set_control_bus_switch(struct intel_encoder *intel_encode return; } -static bool intel_sdvo_set_target_input(struct intel_encoder *intel_encoder, bool target_0, bool target_1) +static bool intel_sdvo_set_target_input(struct intel_sdvo *intel_sdvo, bool target_0, bool target_1) { struct intel_sdvo_set_target_input_args targets = {0}; u8 status; @@ -558,10 +557,10 @@ static bool intel_sdvo_set_target_input(struct intel_encoder *intel_encoder, boo if (target_1) targets.target_1 = 1; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_TARGET_INPUT, &targets, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_TARGET_INPUT, &targets, sizeof(targets)); - status = intel_sdvo_read_response(intel_encoder, NULL, 0); + status = intel_sdvo_read_response(intel_sdvo, NULL, 0); return (status == SDVO_CMD_STATUS_SUCCESS); } @@ -572,13 +571,13 @@ static bool intel_sdvo_set_target_input(struct intel_encoder *intel_encoder, boo * This function is making an assumption about the layout of the response, * which should be checked against the docs. */ -static bool intel_sdvo_get_trained_inputs(struct intel_encoder *intel_encoder, bool *input_1, bool *input_2) +static bool intel_sdvo_get_trained_inputs(struct intel_sdvo *intel_sdvo, bool *input_1, bool *input_2) { struct intel_sdvo_get_trained_inputs_response response; u8 status; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_TRAINED_INPUTS, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, &response, sizeof(response)); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_TRAINED_INPUTS, NULL, 0); + status = intel_sdvo_read_response(intel_sdvo, &response, sizeof(response)); if (status != SDVO_CMD_STATUS_SUCCESS) return false; @@ -587,18 +586,18 @@ static bool intel_sdvo_get_trained_inputs(struct intel_encoder *intel_encoder, b return true; } -static bool intel_sdvo_set_active_outputs(struct intel_encoder *intel_encoder, +static bool intel_sdvo_set_active_outputs(struct intel_sdvo *intel_sdvo, u16 outputs) { u8 status; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_ACTIVE_OUTPUTS, &outputs, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_OUTPUTS, &outputs, sizeof(outputs)); - status = intel_sdvo_read_response(intel_encoder, NULL, 0); + status = intel_sdvo_read_response(intel_sdvo, NULL, 0); return (status == SDVO_CMD_STATUS_SUCCESS); } -static bool intel_sdvo_set_encoder_power_state(struct intel_encoder *intel_encoder, +static bool intel_sdvo_set_encoder_power_state(struct intel_sdvo *intel_sdvo, int mode) { u8 status, state = SDVO_ENCODER_STATE_ON; @@ -618,24 +617,24 @@ static bool intel_sdvo_set_encoder_power_state(struct intel_encoder *intel_encod break; } - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_ENCODER_POWER_STATE, &state, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ENCODER_POWER_STATE, &state, sizeof(state)); - status = intel_sdvo_read_response(intel_encoder, NULL, 0); + status = intel_sdvo_read_response(intel_sdvo, NULL, 0); return (status == SDVO_CMD_STATUS_SUCCESS); } -static bool intel_sdvo_get_input_pixel_clock_range(struct intel_encoder *intel_encoder, +static bool intel_sdvo_get_input_pixel_clock_range(struct intel_sdvo *intel_sdvo, int *clock_min, int *clock_max) { struct intel_sdvo_pixel_clock_range clocks; u8 status; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, &clocks, sizeof(clocks)); + status = intel_sdvo_read_response(intel_sdvo, &clocks, sizeof(clocks)); if (status != SDVO_CMD_STATUS_SUCCESS) return false; @@ -647,58 +646,57 @@ static bool intel_sdvo_get_input_pixel_clock_range(struct intel_encoder *intel_e return true; } -static bool intel_sdvo_set_target_output(struct intel_encoder *intel_encoder, +static bool intel_sdvo_set_target_output(struct intel_sdvo *intel_sdvo, u16 outputs) { u8 status; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_TARGET_OUTPUT, &outputs, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_TARGET_OUTPUT, &outputs, sizeof(outputs)); - status = intel_sdvo_read_response(intel_encoder, NULL, 0); + status = intel_sdvo_read_response(intel_sdvo, NULL, 0); return (status == SDVO_CMD_STATUS_SUCCESS); } -static bool intel_sdvo_set_timing(struct intel_encoder *intel_encoder, u8 cmd, +static bool intel_sdvo_set_timing(struct intel_sdvo *intel_sdvo, u8 cmd, struct intel_sdvo_dtd *dtd) { u8 status; - intel_sdvo_write_cmd(intel_encoder, cmd, &dtd->part1, sizeof(dtd->part1)); - status = intel_sdvo_read_response(intel_encoder, NULL, 0); + intel_sdvo_write_cmd(intel_sdvo, cmd, &dtd->part1, sizeof(dtd->part1)); + status = intel_sdvo_read_response(intel_sdvo, NULL, 0); if (status != SDVO_CMD_STATUS_SUCCESS) return false; - intel_sdvo_write_cmd(intel_encoder, cmd + 1, &dtd->part2, sizeof(dtd->part2)); - status = intel_sdvo_read_response(intel_encoder, NULL, 0); + intel_sdvo_write_cmd(intel_sdvo, cmd + 1, &dtd->part2, sizeof(dtd->part2)); + status = intel_sdvo_read_response(intel_sdvo, NULL, 0); if (status != SDVO_CMD_STATUS_SUCCESS) return false; return true; } -static bool intel_sdvo_set_input_timing(struct intel_encoder *intel_encoder, +static bool intel_sdvo_set_input_timing(struct intel_sdvo *intel_sdvo, struct intel_sdvo_dtd *dtd) { - return intel_sdvo_set_timing(intel_encoder, + return intel_sdvo_set_timing(intel_sdvo, SDVO_CMD_SET_INPUT_TIMINGS_PART1, dtd); } -static bool intel_sdvo_set_output_timing(struct intel_encoder *intel_encoder, +static bool intel_sdvo_set_output_timing(struct intel_sdvo *intel_sdvo, struct intel_sdvo_dtd *dtd) { - return intel_sdvo_set_timing(intel_encoder, + return intel_sdvo_set_timing(intel_sdvo, SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd); } static bool -intel_sdvo_create_preferred_input_timing(struct intel_encoder *intel_encoder, +intel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo, uint16_t clock, uint16_t width, uint16_t height) { struct intel_sdvo_preferred_input_timing_args args; - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; uint8_t status; memset(&args, 0, sizeof(args)); @@ -707,38 +705,38 @@ intel_sdvo_create_preferred_input_timing(struct intel_encoder *intel_encoder, args.height = height; args.interlace = 0; - if (sdvo_priv->is_lvds && - (sdvo_priv->sdvo_lvds_fixed_mode->hdisplay != width || - sdvo_priv->sdvo_lvds_fixed_mode->vdisplay != height)) + if (intel_sdvo->is_lvds && + (intel_sdvo->sdvo_lvds_fixed_mode->hdisplay != width || + intel_sdvo->sdvo_lvds_fixed_mode->vdisplay != height)) args.scaled = 1; - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING, &args, sizeof(args)); - status = intel_sdvo_read_response(intel_encoder, NULL, 0); + status = intel_sdvo_read_response(intel_sdvo, NULL, 0); if (status != SDVO_CMD_STATUS_SUCCESS) return false; return true; } -static bool intel_sdvo_get_preferred_input_timing(struct intel_encoder *intel_encoder, +static bool intel_sdvo_get_preferred_input_timing(struct intel_sdvo *intel_sdvo, struct intel_sdvo_dtd *dtd) { bool status; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, &dtd->part1, + status = intel_sdvo_read_response(intel_sdvo, &dtd->part1, sizeof(dtd->part1)); if (status != SDVO_CMD_STATUS_SUCCESS) return false; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, &dtd->part2, + status = intel_sdvo_read_response(intel_sdvo, &dtd->part2, sizeof(dtd->part2)); if (status != SDVO_CMD_STATUS_SUCCESS) return false; @@ -746,12 +744,12 @@ static bool intel_sdvo_get_preferred_input_timing(struct intel_encoder *intel_en return false; } -static bool intel_sdvo_set_clock_rate_mult(struct intel_encoder *intel_encoder, u8 val) +static bool intel_sdvo_set_clock_rate_mult(struct intel_sdvo *intel_sdvo, u8 val) { u8 status; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1); - status = intel_sdvo_read_response(intel_encoder, NULL, 0); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1); + status = intel_sdvo_read_response(intel_sdvo, NULL, 0); if (status != SDVO_CMD_STATUS_SUCCESS) return false; @@ -840,13 +838,13 @@ static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode, mode->flags |= DRM_MODE_FLAG_PVSYNC; } -static bool intel_sdvo_get_supp_encode(struct intel_encoder *intel_encoder, +static bool intel_sdvo_get_supp_encode(struct intel_sdvo *intel_sdvo, struct intel_sdvo_encode *encode) { uint8_t status; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_SUPP_ENCODE, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, encode, sizeof(*encode)); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_SUPP_ENCODE, NULL, 0); + status = intel_sdvo_read_response(intel_sdvo, encode, sizeof(*encode)); if (status != SDVO_CMD_STATUS_SUCCESS) { /* non-support means DVI */ memset(encode, 0, sizeof(*encode)); return false; @@ -855,30 +853,30 @@ static bool intel_sdvo_get_supp_encode(struct intel_encoder *intel_encoder, return true; } -static bool intel_sdvo_set_encode(struct intel_encoder *intel_encoder, +static bool intel_sdvo_set_encode(struct intel_sdvo *intel_sdvo, uint8_t mode) { uint8_t status; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_ENCODE, &mode, 1); - status = intel_sdvo_read_response(intel_encoder, NULL, 0); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ENCODE, &mode, 1); + status = intel_sdvo_read_response(intel_sdvo, NULL, 0); return (status == SDVO_CMD_STATUS_SUCCESS); } -static bool intel_sdvo_set_colorimetry(struct intel_encoder *intel_encoder, +static bool intel_sdvo_set_colorimetry(struct intel_sdvo *intel_sdvo, uint8_t mode) { uint8_t status; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_COLORIMETRY, &mode, 1); - status = intel_sdvo_read_response(intel_encoder, NULL, 0); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_COLORIMETRY, &mode, 1); + status = intel_sdvo_read_response(intel_sdvo, NULL, 0); return (status == SDVO_CMD_STATUS_SUCCESS); } #if 0 -static void intel_sdvo_dump_hdmi_buf(struct intel_encoder *intel_encoder) +static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo) { int i, j; uint8_t set_buf_index[2]; @@ -908,7 +906,7 @@ static void intel_sdvo_dump_hdmi_buf(struct intel_encoder *intel_encoder) } #endif -static void intel_sdvo_set_hdmi_buf(struct intel_encoder *intel_encoder, +static void intel_sdvo_set_hdmi_buf(struct intel_sdvo *intel_sdvo, int index, uint8_t *data, int8_t size, uint8_t tx_rate) { @@ -917,15 +915,15 @@ static void intel_sdvo_set_hdmi_buf(struct intel_encoder *intel_encoder, set_buf_index[0] = index; set_buf_index[1] = 0; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_HBUF_INDEX, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_INDEX, set_buf_index, 2); for (; size > 0; size -= 8) { - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_HBUF_DATA, data, 8); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_DATA, data, 8); data += 8; } - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_HBUF_TXRATE, &tx_rate, 1); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_TXRATE, &tx_rate, 1); } static uint8_t intel_sdvo_calc_hbuf_csum(uint8_t *data, uint8_t size) @@ -1000,7 +998,7 @@ struct dip_infoframe { } __attribute__ ((packed)) u; } __attribute__((packed)); -static void intel_sdvo_set_avi_infoframe(struct intel_encoder *intel_encoder, +static void intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo, struct drm_display_mode * mode) { struct dip_infoframe avi_if = { @@ -1011,21 +1009,20 @@ static void intel_sdvo_set_avi_infoframe(struct intel_encoder *intel_encoder, avi_if.checksum = intel_sdvo_calc_hbuf_csum((uint8_t *)&avi_if, 4 + avi_if.len); - intel_sdvo_set_hdmi_buf(intel_encoder, 1, (uint8_t *)&avi_if, + intel_sdvo_set_hdmi_buf(intel_sdvo, 1, (uint8_t *)&avi_if, 4 + avi_if.len, SDVO_HBUF_TX_VSYNC); } -static void intel_sdvo_set_tv_format(struct intel_encoder *intel_encoder) +static void intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo) { struct intel_sdvo_tv_format format; - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; uint32_t format_map, i; uint8_t status; for (i = 0; i < TV_FORMAT_NUM; i++) - if (tv_format_names[i] == sdvo_priv->tv_format_name) + if (tv_format_names[i] == intel_sdvo->tv_format_name) break; format_map = 1 << i; @@ -1033,23 +1030,22 @@ static void intel_sdvo_set_tv_format(struct intel_encoder *intel_encoder) memcpy(&format, &format_map, sizeof(format_map) > sizeof(format) ? sizeof(format) : sizeof(format_map)); - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_TV_FORMAT, &format, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_TV_FORMAT, &format, sizeof(format)); - status = intel_sdvo_read_response(intel_encoder, NULL, 0); + status = intel_sdvo_read_response(intel_sdvo, NULL, 0); if (status != SDVO_CMD_STATUS_SUCCESS) DRM_DEBUG_KMS("%s: Failed to set TV format\n", - SDVO_NAME(sdvo_priv)); + SDVO_NAME(intel_sdvo)); } static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_sdvo_priv *dev_priv = intel_encoder->dev_priv; + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); - if (dev_priv->is_tv) { + if (intel_sdvo->is_tv) { struct intel_sdvo_dtd output_dtd; bool success; @@ -1062,25 +1058,25 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, /* Set output timings */ intel_sdvo_get_dtd_from_mode(&output_dtd, mode); - intel_sdvo_set_target_output(intel_encoder, - dev_priv->attached_output); - intel_sdvo_set_output_timing(intel_encoder, &output_dtd); + intel_sdvo_set_target_output(intel_sdvo, + intel_sdvo->attached_output); + intel_sdvo_set_output_timing(intel_sdvo, &output_dtd); /* Set the input timing to the screen. Assume always input 0. */ - intel_sdvo_set_target_input(intel_encoder, true, false); + intel_sdvo_set_target_input(intel_sdvo, true, false); - success = intel_sdvo_create_preferred_input_timing(intel_encoder, + success = intel_sdvo_create_preferred_input_timing(intel_sdvo, mode->clock / 10, mode->hdisplay, mode->vdisplay); if (success) { struct intel_sdvo_dtd input_dtd; - intel_sdvo_get_preferred_input_timing(intel_encoder, + intel_sdvo_get_preferred_input_timing(intel_sdvo, &input_dtd); intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd); - dev_priv->sdvo_flags = input_dtd.part2.sdvo_flags; + intel_sdvo->sdvo_flags = input_dtd.part2.sdvo_flags; drm_mode_set_crtcinfo(adjusted_mode, 0); @@ -1091,25 +1087,25 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, } else { return false; } - } else if (dev_priv->is_lvds) { + } else if (intel_sdvo->is_lvds) { struct intel_sdvo_dtd output_dtd; bool success; - drm_mode_set_crtcinfo(dev_priv->sdvo_lvds_fixed_mode, 0); + drm_mode_set_crtcinfo(intel_sdvo->sdvo_lvds_fixed_mode, 0); /* Set output timings */ intel_sdvo_get_dtd_from_mode(&output_dtd, - dev_priv->sdvo_lvds_fixed_mode); + intel_sdvo->sdvo_lvds_fixed_mode); - intel_sdvo_set_target_output(intel_encoder, - dev_priv->attached_output); - intel_sdvo_set_output_timing(intel_encoder, &output_dtd); + intel_sdvo_set_target_output(intel_sdvo, + intel_sdvo->attached_output); + intel_sdvo_set_output_timing(intel_sdvo, &output_dtd); /* Set the input timing to the screen. Assume always input 0. */ - intel_sdvo_set_target_input(intel_encoder, true, false); + intel_sdvo_set_target_input(intel_sdvo, true, false); success = intel_sdvo_create_preferred_input_timing( - intel_encoder, + intel_sdvo, mode->clock / 10, mode->hdisplay, mode->vdisplay); @@ -1117,10 +1113,10 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, if (success) { struct intel_sdvo_dtd input_dtd; - intel_sdvo_get_preferred_input_timing(intel_encoder, + intel_sdvo_get_preferred_input_timing(intel_sdvo, &input_dtd); intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd); - dev_priv->sdvo_flags = input_dtd.part2.sdvo_flags; + intel_sdvo->sdvo_flags = input_dtd.part2.sdvo_flags; drm_mode_set_crtcinfo(adjusted_mode, 0); @@ -1149,8 +1145,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = encoder->crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); u32 sdvox = 0; int sdvo_pixel_multiply; struct intel_sdvo_in_out_map in_out; @@ -1166,41 +1161,41 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, * channel on the motherboard. In a two-input device, the first input * will be SDVOB and the second SDVOC. */ - in_out.in0 = sdvo_priv->attached_output; + in_out.in0 = intel_sdvo->attached_output; in_out.in1 = 0; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_IN_OUT_MAP, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_IN_OUT_MAP, &in_out, sizeof(in_out)); - status = intel_sdvo_read_response(intel_encoder, NULL, 0); + status = intel_sdvo_read_response(intel_sdvo, NULL, 0); - if (sdvo_priv->is_hdmi) { - intel_sdvo_set_avi_infoframe(intel_encoder, mode); + if (intel_sdvo->is_hdmi) { + intel_sdvo_set_avi_infoframe(intel_sdvo, mode); sdvox |= SDVO_AUDIO_ENABLE; } /* We have tried to get input timing in mode_fixup, and filled into adjusted_mode */ - if (sdvo_priv->is_tv || sdvo_priv->is_lvds) { + if (intel_sdvo->is_tv || intel_sdvo->is_lvds) { intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode); - input_dtd.part2.sdvo_flags = sdvo_priv->sdvo_flags; + input_dtd.part2.sdvo_flags = intel_sdvo->sdvo_flags; } else intel_sdvo_get_dtd_from_mode(&input_dtd, mode); /* If it's a TV, we already set the output timing in mode_fixup. * Otherwise, the output timing is equal to the input timing. */ - if (!sdvo_priv->is_tv && !sdvo_priv->is_lvds) { + if (!intel_sdvo->is_tv && !intel_sdvo->is_lvds) { /* Set the output timing to the screen */ - intel_sdvo_set_target_output(intel_encoder, - sdvo_priv->attached_output); - intel_sdvo_set_output_timing(intel_encoder, &input_dtd); + intel_sdvo_set_target_output(intel_sdvo, + intel_sdvo->attached_output); + intel_sdvo_set_output_timing(intel_sdvo, &input_dtd); } /* Set the input timing to the screen. Assume always input 0. */ - intel_sdvo_set_target_input(intel_encoder, true, false); + intel_sdvo_set_target_input(intel_sdvo, true, false); - if (sdvo_priv->is_tv) - intel_sdvo_set_tv_format(intel_encoder); + if (intel_sdvo->is_tv) + intel_sdvo_set_tv_format(intel_sdvo); /* We would like to use intel_sdvo_create_preferred_input_timing() to * provide the device with a timing it can support, if it supports that @@ -1217,20 +1212,20 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, intel_sdvo_set_input_timing(encoder, &input_dtd); } #else - intel_sdvo_set_input_timing(intel_encoder, &input_dtd); + intel_sdvo_set_input_timing(intel_sdvo, &input_dtd); #endif switch (intel_sdvo_get_pixel_multiplier(mode)) { case 1: - intel_sdvo_set_clock_rate_mult(intel_encoder, + intel_sdvo_set_clock_rate_mult(intel_sdvo, SDVO_CLOCK_RATE_MULT_1X); break; case 2: - intel_sdvo_set_clock_rate_mult(intel_encoder, + intel_sdvo_set_clock_rate_mult(intel_sdvo, SDVO_CLOCK_RATE_MULT_2X); break; case 4: - intel_sdvo_set_clock_rate_mult(intel_encoder, + intel_sdvo_set_clock_rate_mult(intel_sdvo, SDVO_CLOCK_RATE_MULT_4X); break; } @@ -1243,8 +1238,8 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) sdvox |= SDVO_HSYNC_ACTIVE_HIGH; } else { - sdvox |= I915_READ(sdvo_priv->sdvo_reg); - switch (sdvo_priv->sdvo_reg) { + sdvox |= I915_READ(intel_sdvo->sdvo_reg); + switch (intel_sdvo->sdvo_reg) { case SDVOB: sdvox &= SDVOB_PRESERVE_MASK; break; @@ -1266,28 +1261,27 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT; } - if (sdvo_priv->sdvo_flags & SDVO_NEED_TO_STALL) + if (intel_sdvo->sdvo_flags & SDVO_NEED_TO_STALL) sdvox |= SDVO_STALL_SELECT; - intel_sdvo_write_sdvox(intel_encoder, sdvox); + intel_sdvo_write_sdvox(intel_sdvo, sdvox); } static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); u32 temp; if (mode != DRM_MODE_DPMS_ON) { - intel_sdvo_set_active_outputs(intel_encoder, 0); + intel_sdvo_set_active_outputs(intel_sdvo, 0); if (0) - intel_sdvo_set_encoder_power_state(intel_encoder, mode); + intel_sdvo_set_encoder_power_state(intel_sdvo, mode); if (mode == DRM_MODE_DPMS_OFF) { - temp = I915_READ(sdvo_priv->sdvo_reg); + temp = I915_READ(intel_sdvo->sdvo_reg); if ((temp & SDVO_ENABLE) != 0) { - intel_sdvo_write_sdvox(intel_encoder, temp & ~SDVO_ENABLE); + intel_sdvo_write_sdvox(intel_sdvo, temp & ~SDVO_ENABLE); } } } else { @@ -1295,13 +1289,13 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) int i; u8 status; - temp = I915_READ(sdvo_priv->sdvo_reg); + temp = I915_READ(intel_sdvo->sdvo_reg); if ((temp & SDVO_ENABLE) == 0) - intel_sdvo_write_sdvox(intel_encoder, temp | SDVO_ENABLE); + intel_sdvo_write_sdvox(intel_sdvo, temp | SDVO_ENABLE); for (i = 0; i < 2; i++) intel_wait_for_vblank(dev); - status = intel_sdvo_get_trained_inputs(intel_encoder, &input1, + status = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2); @@ -1311,12 +1305,12 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) */ if (status == SDVO_CMD_STATUS_SUCCESS && !input1) { DRM_DEBUG_KMS("First %s output reported failure to " - "sync\n", SDVO_NAME(sdvo_priv)); + "sync\n", SDVO_NAME(intel_sdvo)); } if (0) - intel_sdvo_set_encoder_power_state(intel_encoder, mode); - intel_sdvo_set_active_outputs(intel_encoder, sdvo_priv->attached_output); + intel_sdvo_set_encoder_power_state(intel_sdvo, mode); + intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output); } return; } @@ -1325,38 +1319,37 @@ static int intel_sdvo_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; - if (sdvo_priv->pixel_clock_min > mode->clock) + if (intel_sdvo->pixel_clock_min > mode->clock) return MODE_CLOCK_LOW; - if (sdvo_priv->pixel_clock_max < mode->clock) + if (intel_sdvo->pixel_clock_max < mode->clock) return MODE_CLOCK_HIGH; - if (sdvo_priv->is_lvds == true) { - if (sdvo_priv->sdvo_lvds_fixed_mode == NULL) + if (intel_sdvo->is_lvds == true) { + if (intel_sdvo->sdvo_lvds_fixed_mode == NULL) return MODE_PANEL; - if (mode->hdisplay > sdvo_priv->sdvo_lvds_fixed_mode->hdisplay) + if (mode->hdisplay > intel_sdvo->sdvo_lvds_fixed_mode->hdisplay) return MODE_PANEL; - if (mode->vdisplay > sdvo_priv->sdvo_lvds_fixed_mode->vdisplay) + if (mode->vdisplay > intel_sdvo->sdvo_lvds_fixed_mode->vdisplay) return MODE_PANEL; } return MODE_OK; } -static bool intel_sdvo_get_capabilities(struct intel_encoder *intel_encoder, struct intel_sdvo_caps *caps) +static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct intel_sdvo_caps *caps) { u8 status; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_DEVICE_CAPS, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, caps, sizeof(*caps)); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_DEVICE_CAPS, NULL, 0); + status = intel_sdvo_read_response(intel_sdvo, caps, sizeof(*caps)); if (status != SDVO_CMD_STATUS_SUCCESS) return false; @@ -1368,12 +1361,12 @@ static bool intel_sdvo_get_capabilities(struct intel_encoder *intel_encoder, str struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB) { struct drm_connector *connector = NULL; - struct intel_encoder *iout = NULL; - struct intel_sdvo_priv *sdvo; + struct intel_sdvo *iout = NULL; + struct intel_sdvo *sdvo; /* find the sdvo connector */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - iout = to_intel_encoder(connector); + iout = to_intel_sdvo(connector); if (iout->type != INTEL_OUTPUT_SDVO) continue; @@ -1395,16 +1388,16 @@ int intel_sdvo_supports_hotplug(struct drm_connector *connector) { u8 response[2]; u8 status; - struct intel_encoder *intel_encoder; + struct intel_sdvo *intel_sdvo; DRM_DEBUG_KMS("\n"); if (!connector) return 0; - intel_encoder = to_intel_encoder(connector); + intel_sdvo = to_intel_sdvo(connector); - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, &response, 2); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); + status = intel_sdvo_read_response(intel_sdvo, &response, 2); if (response[0] !=0) return 1; @@ -1416,54 +1409,53 @@ void intel_sdvo_set_hotplug(struct drm_connector *connector, int on) { u8 response[2]; u8 status; - struct intel_encoder *intel_encoder = to_intel_encoder(connector); + struct intel_sdvo *intel_sdvo = to_intel_sdvo(connector); - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); - intel_sdvo_read_response(intel_encoder, &response, 2); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); + intel_sdvo_read_response(intel_sdvo, &response, 2); if (on) { - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, &response, 2); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); + status = intel_sdvo_read_response(intel_sdvo, &response, 2); - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); } else { response[0] = 0; response[1] = 0; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); } - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); - intel_sdvo_read_response(intel_encoder, &response, 2); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); + intel_sdvo_read_response(intel_sdvo, &response, 2); } #endif static bool -intel_sdvo_multifunc_encoder(struct intel_encoder *intel_encoder) +intel_sdvo_multifunc_encoder(struct intel_sdvo *intel_sdvo) { - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; int caps = 0; - if (sdvo_priv->caps.output_flags & + if (intel_sdvo->caps.output_flags & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) caps++; - if (sdvo_priv->caps.output_flags & + if (intel_sdvo->caps.output_flags & (SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1)) caps++; - if (sdvo_priv->caps.output_flags & + if (intel_sdvo->caps.output_flags & (SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_SVID1)) caps++; - if (sdvo_priv->caps.output_flags & + if (intel_sdvo->caps.output_flags & (SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_CVBS1)) caps++; - if (sdvo_priv->caps.output_flags & + if (intel_sdvo->caps.output_flags & (SDVO_OUTPUT_YPRPB0 | SDVO_OUTPUT_YPRPB1)) caps++; - if (sdvo_priv->caps.output_flags & + if (intel_sdvo->caps.output_flags & (SDVO_OUTPUT_SCART0 | SDVO_OUTPUT_SCART1)) caps++; - if (sdvo_priv->caps.output_flags & + if (intel_sdvo->caps.output_flags & (SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1)) caps++; @@ -1475,11 +1467,11 @@ intel_find_analog_connector(struct drm_device *dev) { struct drm_connector *connector; struct drm_encoder *encoder; - struct intel_encoder *intel_encoder; + struct intel_sdvo *intel_sdvo; list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - intel_encoder = enc_to_intel_encoder(encoder); - if (intel_encoder->type == INTEL_OUTPUT_ANALOG) { + intel_sdvo = enc_to_intel_sdvo(encoder); + if (intel_sdvo->base.type == INTEL_OUTPUT_ANALOG) { list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (encoder == intel_attached_encoder(connector)) return connector; @@ -1509,46 +1501,45 @@ enum drm_connector_status intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); struct intel_connector *intel_connector = to_intel_connector(connector); struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; enum drm_connector_status status = connector_status_connected; struct edid *edid = NULL; - edid = drm_get_edid(connector, intel_encoder->ddc_bus); + edid = drm_get_edid(connector, intel_sdvo->base.ddc_bus); /* This is only applied to SDVO cards with multiple outputs */ - if (edid == NULL && intel_sdvo_multifunc_encoder(intel_encoder)) { + if (edid == NULL && intel_sdvo_multifunc_encoder(intel_sdvo)) { uint8_t saved_ddc, temp_ddc; - saved_ddc = sdvo_priv->ddc_bus; - temp_ddc = sdvo_priv->ddc_bus >> 1; + saved_ddc = intel_sdvo->ddc_bus; + temp_ddc = intel_sdvo->ddc_bus >> 1; /* * Don't use the 1 as the argument of DDC bus switch to get * the EDID. It is used for SDVO SPD ROM. */ while(temp_ddc > 1) { - sdvo_priv->ddc_bus = temp_ddc; - edid = drm_get_edid(connector, intel_encoder->ddc_bus); + intel_sdvo->ddc_bus = temp_ddc; + edid = drm_get_edid(connector, intel_sdvo->base.ddc_bus); if (edid) { /* * When we can get the EDID, maybe it is the * correct DDC bus. Update it. */ - sdvo_priv->ddc_bus = temp_ddc; + intel_sdvo->ddc_bus = temp_ddc; break; } temp_ddc >>= 1; } if (edid == NULL) - sdvo_priv->ddc_bus = saved_ddc; + intel_sdvo->ddc_bus = saved_ddc; } /* when there is no edid and no monitor is connected with VGA * port, try to use the CRT ddc to read the EDID for DVI-connector */ - if (edid == NULL && sdvo_priv->analog_ddc_bus && + if (edid == NULL && intel_sdvo->analog_ddc_bus && !intel_analog_is_connected(connector->dev)) - edid = drm_get_edid(connector, sdvo_priv->analog_ddc_bus); + edid = drm_get_edid(connector, intel_sdvo->analog_ddc_bus); if (edid != NULL) { bool is_digital = !!(edid->input & DRM_EDID_INPUT_DIGITAL); @@ -1556,7 +1547,7 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) /* DDC bus is shared, match EDID to connector type */ if (is_digital && need_digital) - sdvo_priv->is_hdmi = drm_detect_hdmi_monitor(edid); + intel_sdvo->is_hdmi = drm_detect_hdmi_monitor(edid); else if (is_digital != need_digital) status = connector_status_disconnected; @@ -1574,19 +1565,18 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect uint16_t response; u8 status; struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; enum drm_connector_status ret; - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0); - if (sdvo_priv->is_tv) { + if (intel_sdvo->is_tv) { /* add 30ms delay when the output type is SDVO-TV */ mdelay(30); } - status = intel_sdvo_read_response(intel_encoder, &response, 2); + status = intel_sdvo_read_response(intel_sdvo, &response, 2); DRM_DEBUG_KMS("SDVO response %d %d\n", response & 0xff, response >> 8); @@ -1596,7 +1586,7 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect if (response == 0) return connector_status_disconnected; - sdvo_priv->attached_output = response; + intel_sdvo->attached_output = response; if ((sdvo_connector->output_flag & response) == 0) ret = connector_status_disconnected; @@ -1607,16 +1597,16 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect /* May update encoder flag for like clock for SDVO TV, etc.*/ if (ret == connector_status_connected) { - sdvo_priv->is_tv = false; - sdvo_priv->is_lvds = false; - intel_encoder->needs_tv_clock = false; + intel_sdvo->is_tv = false; + intel_sdvo->is_lvds = false; + intel_sdvo->base.needs_tv_clock = false; if (response & SDVO_TV_MASK) { - sdvo_priv->is_tv = true; - intel_encoder->needs_tv_clock = true; + intel_sdvo->is_tv = true; + intel_sdvo->base.needs_tv_clock = true; } if (response & SDVO_LVDS_MASK) - sdvo_priv->is_lvds = true; + intel_sdvo->is_lvds = true; } return ret; @@ -1625,12 +1615,11 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); int num_modes; /* set the bus switch and get the modes */ - num_modes = intel_ddc_get_modes(connector, intel_encoder->ddc_bus); + num_modes = intel_ddc_get_modes(connector, intel_sdvo->base.ddc_bus); /* * Mac mini hack. On this device, the DVI-I connector shares one DDC @@ -1639,11 +1628,11 @@ static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) * which case we'll look there for the digital DDC data. */ if (num_modes == 0 && - sdvo_priv->analog_ddc_bus && + intel_sdvo->analog_ddc_bus && !intel_analog_is_connected(connector->dev)) { /* Switch to the analog ddc bus and try that */ - (void) intel_ddc_get_modes(connector, sdvo_priv->analog_ddc_bus); + (void) intel_ddc_get_modes(connector, intel_sdvo->analog_ddc_bus); } } @@ -1715,8 +1704,7 @@ struct drm_display_mode sdvo_tv_modes[] = { static void intel_sdvo_get_tv_modes(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); struct intel_sdvo_sdtv_resolution_request tv_res; uint32_t reply = 0, format_map = 0; int i; @@ -1727,7 +1715,7 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) * format. */ for (i = 0; i < TV_FORMAT_NUM; i++) - if (tv_format_names[i] == sdvo_priv->tv_format_name) + if (tv_format_names[i] == intel_sdvo->tv_format_name) break; format_map = (1 << i); @@ -1736,11 +1724,11 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) sizeof(format_map) ? sizeof(format_map) : sizeof(struct intel_sdvo_sdtv_resolution_request)); - intel_sdvo_set_target_output(intel_encoder, sdvo_priv->attached_output); + intel_sdvo_set_target_output(intel_sdvo, intel_sdvo->attached_output); - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT, &tv_res, sizeof(tv_res)); - status = intel_sdvo_read_response(intel_encoder, &reply, 3); + status = intel_sdvo_read_response(intel_sdvo, &reply, 3); if (status != SDVO_CMD_STATUS_SUCCESS) return; @@ -1758,9 +1746,8 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); struct drm_i915_private *dev_priv = connector->dev->dev_private; - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; struct drm_display_mode *newmode; /* @@ -1768,7 +1755,7 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) * Assume that the preferred modes are * arranged in priority order. */ - intel_ddc_get_modes(connector, intel_encoder->ddc_bus); + intel_ddc_get_modes(connector, intel_sdvo->base.ddc_bus); if (list_empty(&connector->probed_modes) == false) goto end; @@ -1787,7 +1774,7 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) end: list_for_each_entry(newmode, &connector->probed_modes, head) { if (newmode->type & DRM_MODE_TYPE_PREFERRED) { - sdvo_priv->sdvo_lvds_fixed_mode = + intel_sdvo->sdvo_lvds_fixed_mode = drm_mode_duplicate(connector->dev, newmode); break; } @@ -1816,35 +1803,35 @@ static void intel_sdvo_destroy_enhance_property(struct drm_connector *connector) { struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_connector *sdvo_priv = intel_connector->dev_priv; + struct intel_sdvo_connector *intel_sdvo = intel_connector->dev_priv; struct drm_device *dev = connector->dev; - if (IS_TV(sdvo_priv)) { - if (sdvo_priv->left_property) - drm_property_destroy(dev, sdvo_priv->left_property); - if (sdvo_priv->right_property) - drm_property_destroy(dev, sdvo_priv->right_property); - if (sdvo_priv->top_property) - drm_property_destroy(dev, sdvo_priv->top_property); - if (sdvo_priv->bottom_property) - drm_property_destroy(dev, sdvo_priv->bottom_property); - if (sdvo_priv->hpos_property) - drm_property_destroy(dev, sdvo_priv->hpos_property); - if (sdvo_priv->vpos_property) - drm_property_destroy(dev, sdvo_priv->vpos_property); - if (sdvo_priv->saturation_property) + if (IS_TV(intel_sdvo)) { + if (intel_sdvo->left_property) + drm_property_destroy(dev, intel_sdvo->left_property); + if (intel_sdvo->right_property) + drm_property_destroy(dev, intel_sdvo->right_property); + if (intel_sdvo->top_property) + drm_property_destroy(dev, intel_sdvo->top_property); + if (intel_sdvo->bottom_property) + drm_property_destroy(dev, intel_sdvo->bottom_property); + if (intel_sdvo->hpos_property) + drm_property_destroy(dev, intel_sdvo->hpos_property); + if (intel_sdvo->vpos_property) + drm_property_destroy(dev, intel_sdvo->vpos_property); + if (intel_sdvo->saturation_property) drm_property_destroy(dev, - sdvo_priv->saturation_property); - if (sdvo_priv->contrast_property) + intel_sdvo->saturation_property); + if (intel_sdvo->contrast_property) drm_property_destroy(dev, - sdvo_priv->contrast_property); - if (sdvo_priv->hue_property) - drm_property_destroy(dev, sdvo_priv->hue_property); + intel_sdvo->contrast_property); + if (intel_sdvo->hue_property) + drm_property_destroy(dev, intel_sdvo->hue_property); } - if (IS_TV(sdvo_priv) || IS_LVDS(sdvo_priv)) { - if (sdvo_priv->brightness_property) + if (IS_TV(intel_sdvo) || IS_LVDS(intel_sdvo)) { + if (intel_sdvo->brightness_property) drm_property_destroy(dev, - sdvo_priv->brightness_property); + intel_sdvo->brightness_property); } return; } @@ -1870,8 +1857,7 @@ intel_sdvo_set_property(struct drm_connector *connector, uint64_t val) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); struct intel_connector *intel_connector = to_intel_connector(connector); struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; struct drm_crtc *crtc = encoder->crtc; @@ -1889,11 +1875,11 @@ intel_sdvo_set_property(struct drm_connector *connector, ret = -EINVAL; goto out; } - if (sdvo_priv->tv_format_name == + if (intel_sdvo->tv_format_name == sdvo_connector->tv_format_supported[val]) goto out; - sdvo_priv->tv_format_name = sdvo_connector->tv_format_supported[val]; + intel_sdvo->tv_format_name = sdvo_connector->tv_format_supported[val]; changed = true; } @@ -1981,8 +1967,8 @@ intel_sdvo_set_property(struct drm_connector *connector, sdvo_connector->cur_brightness = temp_value; } if (cmd) { - intel_sdvo_write_cmd(intel_encoder, cmd, &temp_value, 2); - status = intel_sdvo_read_response(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, cmd, &temp_value, 2); + status = intel_sdvo_read_response(intel_sdvo, NULL, 0); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO command \n"); @@ -2022,22 +2008,16 @@ static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs static void intel_sdvo_enc_destroy(struct drm_encoder *encoder) { - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); - if (intel_encoder->i2c_bus) - intel_i2c_destroy(intel_encoder->i2c_bus); - if (intel_encoder->ddc_bus) - intel_i2c_destroy(intel_encoder->ddc_bus); - if (sdvo_priv->analog_ddc_bus) - intel_i2c_destroy(sdvo_priv->analog_ddc_bus); + if (intel_sdvo->analog_ddc_bus) + intel_i2c_destroy(intel_sdvo->analog_ddc_bus); - if (sdvo_priv->sdvo_lvds_fixed_mode != NULL) + if (intel_sdvo->sdvo_lvds_fixed_mode != NULL) drm_mode_destroy(encoder->dev, - sdvo_priv->sdvo_lvds_fixed_mode); + intel_sdvo->sdvo_lvds_fixed_mode); - drm_encoder_cleanup(encoder); - kfree(intel_encoder); + intel_encoder_destroy(encoder); } static const struct drm_encoder_funcs intel_sdvo_enc_funcs = { @@ -2054,7 +2034,7 @@ static const struct drm_encoder_funcs intel_sdvo_enc_funcs = { */ static void intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv, - struct intel_sdvo_priv *sdvo, u32 reg) + struct intel_sdvo *sdvo, u32 reg) { struct sdvo_device_mapping *mapping; @@ -2067,57 +2047,54 @@ intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv, } static bool -intel_sdvo_get_digital_encoding_mode(struct intel_encoder *output, int device) +intel_sdvo_get_digital_encoding_mode(struct intel_sdvo *intel_sdvo, int device) { - struct intel_sdvo_priv *sdvo_priv = output->dev_priv; uint8_t status; if (device == 0) - intel_sdvo_set_target_output(output, SDVO_OUTPUT_TMDS0); + intel_sdvo_set_target_output(intel_sdvo, SDVO_OUTPUT_TMDS0); else - intel_sdvo_set_target_output(output, SDVO_OUTPUT_TMDS1); + intel_sdvo_set_target_output(intel_sdvo, SDVO_OUTPUT_TMDS1); - intel_sdvo_write_cmd(output, SDVO_CMD_GET_ENCODE, NULL, 0); - status = intel_sdvo_read_response(output, &sdvo_priv->is_hdmi, 1); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_ENCODE, NULL, 0); + status = intel_sdvo_read_response(intel_sdvo, &intel_sdvo->is_hdmi, 1); if (status != SDVO_CMD_STATUS_SUCCESS) return false; return true; } -static struct intel_encoder * -intel_sdvo_chan_to_intel_encoder(struct intel_i2c_chan *chan) +static struct intel_sdvo * +intel_sdvo_chan_to_intel_sdvo(struct intel_i2c_chan *chan) { struct drm_device *dev = chan->drm_dev; struct drm_encoder *encoder; - struct intel_encoder *intel_encoder = NULL; list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - intel_encoder = enc_to_intel_encoder(encoder); - if (intel_encoder->ddc_bus == &chan->adapter) - break; + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); + if (intel_sdvo->base.ddc_bus == &chan->adapter) + return intel_sdvo; } - return intel_encoder; + + return NULL;; } static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) { - struct intel_encoder *intel_encoder; - struct intel_sdvo_priv *sdvo_priv; + struct intel_sdvo *intel_sdvo; struct i2c_algo_bit_data *algo_data; const struct i2c_algorithm *algo; algo_data = (struct i2c_algo_bit_data *)i2c_adap->algo_data; - intel_encoder = - intel_sdvo_chan_to_intel_encoder( - (struct intel_i2c_chan *)(algo_data->data)); - if (intel_encoder == NULL) + intel_sdvo = + intel_sdvo_chan_to_intel_sdvo((struct intel_i2c_chan *) + (algo_data->data)); + if (intel_sdvo == NULL) return -EINVAL; - sdvo_priv = intel_encoder->dev_priv; - algo = intel_encoder->i2c_bus->algo; + algo = intel_sdvo->base.i2c_bus->algo; - intel_sdvo_set_control_bus_switch(intel_encoder, sdvo_priv->ddc_bus); + intel_sdvo_set_control_bus_switch(intel_sdvo, intel_sdvo->ddc_bus); return algo->master_xfer(i2c_adap, msgs, num); } @@ -2198,10 +2175,9 @@ intel_sdvo_connector_create (struct drm_encoder *encoder, } static bool -intel_sdvo_dvi_init(struct intel_encoder *intel_encoder, int device) +intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) { - struct drm_encoder *encoder = &intel_encoder->enc; - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct drm_encoder *encoder = &intel_sdvo->base.enc; struct drm_connector *connector; struct intel_connector *intel_connector; struct intel_sdvo_connector *sdvo_connector; @@ -2212,10 +2188,10 @@ intel_sdvo_dvi_init(struct intel_encoder *intel_encoder, int device) sdvo_connector = intel_connector->dev_priv; if (device == 0) { - sdvo_priv->controlled_output |= SDVO_OUTPUT_TMDS0; + intel_sdvo->controlled_output |= SDVO_OUTPUT_TMDS0; sdvo_connector->output_flag = SDVO_OUTPUT_TMDS0; } else if (device == 1) { - sdvo_priv->controlled_output |= SDVO_OUTPUT_TMDS1; + intel_sdvo->controlled_output |= SDVO_OUTPUT_TMDS1; sdvo_connector->output_flag = SDVO_OUTPUT_TMDS1; } @@ -2224,17 +2200,17 @@ intel_sdvo_dvi_init(struct intel_encoder *intel_encoder, int device) encoder->encoder_type = DRM_MODE_ENCODER_TMDS; connector->connector_type = DRM_MODE_CONNECTOR_DVID; - if (intel_sdvo_get_supp_encode(intel_encoder, &sdvo_priv->encode) - && intel_sdvo_get_digital_encoding_mode(intel_encoder, device) - && sdvo_priv->is_hdmi) { + if (intel_sdvo_get_supp_encode(intel_sdvo, &intel_sdvo->encode) + && intel_sdvo_get_digital_encoding_mode(intel_sdvo, device) + && intel_sdvo->is_hdmi) { /* enable hdmi encoding mode if supported */ - intel_sdvo_set_encode(intel_encoder, SDVO_ENCODE_HDMI); - intel_sdvo_set_colorimetry(intel_encoder, + intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI); + intel_sdvo_set_colorimetry(intel_sdvo, SDVO_COLORIMETRY_RGB256); connector->connector_type = DRM_MODE_CONNECTOR_HDMIA; } - intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) | - (1 << INTEL_ANALOG_CLONE_BIT); + intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) | + (1 << INTEL_ANALOG_CLONE_BIT)); intel_sdvo_connector_create(encoder, connector); @@ -2242,10 +2218,9 @@ intel_sdvo_dvi_init(struct intel_encoder *intel_encoder, int device) } static bool -intel_sdvo_tv_init(struct intel_encoder *intel_encoder, int type) +intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type) { - struct drm_encoder *encoder = &intel_encoder->enc; - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct drm_encoder *encoder = &intel_sdvo->base.enc; struct drm_connector *connector; struct intel_connector *intel_connector; struct intel_sdvo_connector *sdvo_connector; @@ -2258,12 +2233,12 @@ intel_sdvo_tv_init(struct intel_encoder *intel_encoder, int type) connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO; sdvo_connector = intel_connector->dev_priv; - sdvo_priv->controlled_output |= type; + intel_sdvo->controlled_output |= type; sdvo_connector->output_flag = type; - sdvo_priv->is_tv = true; - intel_encoder->needs_tv_clock = true; - intel_encoder->clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT; + intel_sdvo->is_tv = true; + intel_sdvo->base.needs_tv_clock = true; + intel_sdvo->base.clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT; intel_sdvo_connector_create(encoder, connector); @@ -2275,10 +2250,9 @@ intel_sdvo_tv_init(struct intel_encoder *intel_encoder, int type) } static bool -intel_sdvo_analog_init(struct intel_encoder *intel_encoder, int device) +intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device) { - struct drm_encoder *encoder = &intel_encoder->enc; - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct drm_encoder *encoder = &intel_sdvo->base.enc; struct drm_connector *connector; struct intel_connector *intel_connector; struct intel_sdvo_connector *sdvo_connector; @@ -2293,25 +2267,24 @@ intel_sdvo_analog_init(struct intel_encoder *intel_encoder, int device) sdvo_connector = intel_connector->dev_priv; if (device == 0) { - sdvo_priv->controlled_output |= SDVO_OUTPUT_RGB0; + intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB0; sdvo_connector->output_flag = SDVO_OUTPUT_RGB0; } else if (device == 1) { - sdvo_priv->controlled_output |= SDVO_OUTPUT_RGB1; + intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB1; sdvo_connector->output_flag = SDVO_OUTPUT_RGB1; } - intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) | - (1 << INTEL_ANALOG_CLONE_BIT); + intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) | + (1 << INTEL_ANALOG_CLONE_BIT)); intel_sdvo_connector_create(encoder, connector); return true; } static bool -intel_sdvo_lvds_init(struct intel_encoder *intel_encoder, int device) +intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) { - struct drm_encoder *encoder = &intel_encoder->enc; - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct drm_encoder *encoder = &intel_sdvo->base.enc; struct drm_connector *connector; struct intel_connector *intel_connector; struct intel_sdvo_connector *sdvo_connector; @@ -2324,18 +2297,18 @@ intel_sdvo_lvds_init(struct intel_encoder *intel_encoder, int device) connector->connector_type = DRM_MODE_CONNECTOR_LVDS; sdvo_connector = intel_connector->dev_priv; - sdvo_priv->is_lvds = true; + intel_sdvo->is_lvds = true; if (device == 0) { - sdvo_priv->controlled_output |= SDVO_OUTPUT_LVDS0; + intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS0; sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0; } else if (device == 1) { - sdvo_priv->controlled_output |= SDVO_OUTPUT_LVDS1; + intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS1; sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1; } - intel_encoder->clone_mask = (1 << INTEL_ANALOG_CLONE_BIT) | - (1 << INTEL_SDVO_LVDS_CLONE_BIT); + intel_sdvo->base.clone_mask = ((1 << INTEL_ANALOG_CLONE_BIT) | + (1 << INTEL_SDVO_LVDS_CLONE_BIT)); intel_sdvo_connector_create(encoder, connector); intel_sdvo_create_enhance_property(connector); @@ -2343,60 +2316,58 @@ intel_sdvo_lvds_init(struct intel_encoder *intel_encoder, int device) } static bool -intel_sdvo_output_setup(struct intel_encoder *intel_encoder, uint16_t flags) +intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags) { - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; - - sdvo_priv->is_tv = false; - intel_encoder->needs_tv_clock = false; - sdvo_priv->is_lvds = false; + intel_sdvo->is_tv = false; + intel_sdvo->base.needs_tv_clock = false; + intel_sdvo->is_lvds = false; /* SDVO requires XXX1 function may not exist unless it has XXX0 function.*/ if (flags & SDVO_OUTPUT_TMDS0) - if (!intel_sdvo_dvi_init(intel_encoder, 0)) + if (!intel_sdvo_dvi_init(intel_sdvo, 0)) return false; if ((flags & SDVO_TMDS_MASK) == SDVO_TMDS_MASK) - if (!intel_sdvo_dvi_init(intel_encoder, 1)) + if (!intel_sdvo_dvi_init(intel_sdvo, 1)) return false; /* TV has no XXX1 function block */ if (flags & SDVO_OUTPUT_SVID0) - if (!intel_sdvo_tv_init(intel_encoder, SDVO_OUTPUT_SVID0)) + if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_SVID0)) return false; if (flags & SDVO_OUTPUT_CVBS0) - if (!intel_sdvo_tv_init(intel_encoder, SDVO_OUTPUT_CVBS0)) + if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_CVBS0)) return false; if (flags & SDVO_OUTPUT_RGB0) - if (!intel_sdvo_analog_init(intel_encoder, 0)) + if (!intel_sdvo_analog_init(intel_sdvo, 0)) return false; if ((flags & SDVO_RGB_MASK) == SDVO_RGB_MASK) - if (!intel_sdvo_analog_init(intel_encoder, 1)) + if (!intel_sdvo_analog_init(intel_sdvo, 1)) return false; if (flags & SDVO_OUTPUT_LVDS0) - if (!intel_sdvo_lvds_init(intel_encoder, 0)) + if (!intel_sdvo_lvds_init(intel_sdvo, 0)) return false; if ((flags & SDVO_LVDS_MASK) == SDVO_LVDS_MASK) - if (!intel_sdvo_lvds_init(intel_encoder, 1)) + if (!intel_sdvo_lvds_init(intel_sdvo, 1)) return false; if ((flags & SDVO_OUTPUT_MASK) == 0) { unsigned char bytes[2]; - sdvo_priv->controlled_output = 0; - memcpy(bytes, &sdvo_priv->caps.output_flags, 2); + intel_sdvo->controlled_output = 0; + memcpy(bytes, &intel_sdvo->caps.output_flags, 2); DRM_DEBUG_KMS("%s: Unknown SDVO output type (0x%02x%02x)\n", - SDVO_NAME(sdvo_priv), + SDVO_NAME(intel_sdvo), bytes[0], bytes[1]); return false; } - intel_encoder->crtc_mask = (1 << 0) | (1 << 1); + intel_sdvo->base.crtc_mask = (1 << 0) | (1 << 1); return true; } @@ -2404,19 +2375,18 @@ intel_sdvo_output_setup(struct intel_encoder *intel_encoder, uint16_t flags) static void intel_sdvo_tv_create_property(struct drm_connector *connector, int type) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); struct intel_connector *intel_connector = to_intel_connector(connector); struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; struct intel_sdvo_tv_format format; uint32_t format_map, i; uint8_t status; - intel_sdvo_set_target_output(intel_encoder, type); + intel_sdvo_set_target_output(intel_sdvo, type); - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_SUPPORTED_TV_FORMATS, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &format, sizeof(format)); if (status != SDVO_CMD_STATUS_SUCCESS) return; @@ -2446,7 +2416,7 @@ static void intel_sdvo_tv_create_property(struct drm_connector *connector, int t sdvo_connector->tv_format_property, i, i, sdvo_connector->tv_format_supported[i]); - sdvo_priv->tv_format_name = sdvo_connector->tv_format_supported[0]; + intel_sdvo->tv_format_name = sdvo_connector->tv_format_supported[0]; drm_connector_attach_property( connector, sdvo_connector->tv_format_property, 0); @@ -2455,17 +2425,17 @@ static void intel_sdvo_tv_create_property(struct drm_connector *connector, int t static void intel_sdvo_create_enhance_property(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_connector *sdvo_priv = intel_connector->dev_priv; + struct intel_sdvo_connector *intel_sdvo_connector = intel_connector->dev_priv; struct intel_sdvo_enhancements_reply sdvo_data; struct drm_device *dev = connector->dev; uint8_t status; uint16_t response, data_value[2]; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, &sdvo_data, + status = intel_sdvo_read_response(intel_sdvo, &sdvo_data, sizeof(sdvo_data)); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS(" incorrect response is returned\n"); @@ -2476,278 +2446,278 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) DRM_DEBUG_KMS("No enhancement is supported\n"); return; } - if (IS_TV(sdvo_priv)) { + if (IS_TV(intel_sdvo_connector)) { /* when horizontal overscan is supported, Add the left/right * property */ if (sdvo_data.overscan_h) { - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_MAX_OVERSCAN_H, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &data_value, 4); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO max " "h_overscan\n"); return; } - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_OVERSCAN_H, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &response, 2); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO h_overscan\n"); return; } - sdvo_priv->max_hscan = data_value[0]; - sdvo_priv->left_margin = data_value[0] - response; - sdvo_priv->right_margin = sdvo_priv->left_margin; - sdvo_priv->left_property = + intel_sdvo_connector->max_hscan = data_value[0]; + intel_sdvo_connector->left_margin = data_value[0] - response; + intel_sdvo_connector->right_margin = intel_sdvo_connector->left_margin; + intel_sdvo_connector->left_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "left_margin", 2); - sdvo_priv->left_property->values[0] = 0; - sdvo_priv->left_property->values[1] = data_value[0]; + intel_sdvo_connector->left_property->values[0] = 0; + intel_sdvo_connector->left_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->left_property, - sdvo_priv->left_margin); - sdvo_priv->right_property = + intel_sdvo_connector->left_property, + intel_sdvo_connector->left_margin); + intel_sdvo_connector->right_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "right_margin", 2); - sdvo_priv->right_property->values[0] = 0; - sdvo_priv->right_property->values[1] = data_value[0]; + intel_sdvo_connector->right_property->values[0] = 0; + intel_sdvo_connector->right_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->right_property, - sdvo_priv->right_margin); + intel_sdvo_connector->right_property, + intel_sdvo_connector->right_margin); DRM_DEBUG_KMS("h_overscan: max %d, " "default %d, current %d\n", data_value[0], data_value[1], response); } if (sdvo_data.overscan_v) { - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_MAX_OVERSCAN_V, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &data_value, 4); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO max " "v_overscan\n"); return; } - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_OVERSCAN_V, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &response, 2); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO v_overscan\n"); return; } - sdvo_priv->max_vscan = data_value[0]; - sdvo_priv->top_margin = data_value[0] - response; - sdvo_priv->bottom_margin = sdvo_priv->top_margin; - sdvo_priv->top_property = + intel_sdvo_connector->max_vscan = data_value[0]; + intel_sdvo_connector->top_margin = data_value[0] - response; + intel_sdvo_connector->bottom_margin = intel_sdvo_connector->top_margin; + intel_sdvo_connector->top_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "top_margin", 2); - sdvo_priv->top_property->values[0] = 0; - sdvo_priv->top_property->values[1] = data_value[0]; + intel_sdvo_connector->top_property->values[0] = 0; + intel_sdvo_connector->top_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->top_property, - sdvo_priv->top_margin); - sdvo_priv->bottom_property = + intel_sdvo_connector->top_property, + intel_sdvo_connector->top_margin); + intel_sdvo_connector->bottom_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "bottom_margin", 2); - sdvo_priv->bottom_property->values[0] = 0; - sdvo_priv->bottom_property->values[1] = data_value[0]; + intel_sdvo_connector->bottom_property->values[0] = 0; + intel_sdvo_connector->bottom_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->bottom_property, - sdvo_priv->bottom_margin); + intel_sdvo_connector->bottom_property, + intel_sdvo_connector->bottom_margin); DRM_DEBUG_KMS("v_overscan: max %d, " "default %d, current %d\n", data_value[0], data_value[1], response); } if (sdvo_data.position_h) { - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_MAX_POSITION_H, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &data_value, 4); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO Max h_pos\n"); return; } - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_POSITION_H, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &response, 2); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO get h_postion\n"); return; } - sdvo_priv->max_hpos = data_value[0]; - sdvo_priv->cur_hpos = response; - sdvo_priv->hpos_property = + intel_sdvo_connector->max_hpos = data_value[0]; + intel_sdvo_connector->cur_hpos = response; + intel_sdvo_connector->hpos_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "hpos", 2); - sdvo_priv->hpos_property->values[0] = 0; - sdvo_priv->hpos_property->values[1] = data_value[0]; + intel_sdvo_connector->hpos_property->values[0] = 0; + intel_sdvo_connector->hpos_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->hpos_property, - sdvo_priv->cur_hpos); + intel_sdvo_connector->hpos_property, + intel_sdvo_connector->cur_hpos); DRM_DEBUG_KMS("h_position: max %d, " "default %d, current %d\n", data_value[0], data_value[1], response); } if (sdvo_data.position_v) { - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_MAX_POSITION_V, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &data_value, 4); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO Max v_pos\n"); return; } - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_POSITION_V, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &response, 2); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO get v_postion\n"); return; } - sdvo_priv->max_vpos = data_value[0]; - sdvo_priv->cur_vpos = response; - sdvo_priv->vpos_property = + intel_sdvo_connector->max_vpos = data_value[0]; + intel_sdvo_connector->cur_vpos = response; + intel_sdvo_connector->vpos_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "vpos", 2); - sdvo_priv->vpos_property->values[0] = 0; - sdvo_priv->vpos_property->values[1] = data_value[0]; + intel_sdvo_connector->vpos_property->values[0] = 0; + intel_sdvo_connector->vpos_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->vpos_property, - sdvo_priv->cur_vpos); + intel_sdvo_connector->vpos_property, + intel_sdvo_connector->cur_vpos); DRM_DEBUG_KMS("v_position: max %d, " "default %d, current %d\n", data_value[0], data_value[1], response); } if (sdvo_data.saturation) { - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_MAX_SATURATION, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &data_value, 4); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO Max sat\n"); return; } - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_SATURATION, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &response, 2); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO get sat\n"); return; } - sdvo_priv->max_saturation = data_value[0]; - sdvo_priv->cur_saturation = response; - sdvo_priv->saturation_property = + intel_sdvo_connector->max_saturation = data_value[0]; + intel_sdvo_connector->cur_saturation = response; + intel_sdvo_connector->saturation_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "saturation", 2); - sdvo_priv->saturation_property->values[0] = 0; - sdvo_priv->saturation_property->values[1] = + intel_sdvo_connector->saturation_property->values[0] = 0; + intel_sdvo_connector->saturation_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->saturation_property, - sdvo_priv->cur_saturation); + intel_sdvo_connector->saturation_property, + intel_sdvo_connector->cur_saturation); DRM_DEBUG_KMS("saturation: max %d, " "default %d, current %d\n", data_value[0], data_value[1], response); } if (sdvo_data.contrast) { - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_MAX_CONTRAST, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &data_value, 4); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO Max contrast\n"); return; } - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_CONTRAST, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &response, 2); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO get contrast\n"); return; } - sdvo_priv->max_contrast = data_value[0]; - sdvo_priv->cur_contrast = response; - sdvo_priv->contrast_property = + intel_sdvo_connector->max_contrast = data_value[0]; + intel_sdvo_connector->cur_contrast = response; + intel_sdvo_connector->contrast_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "contrast", 2); - sdvo_priv->contrast_property->values[0] = 0; - sdvo_priv->contrast_property->values[1] = data_value[0]; + intel_sdvo_connector->contrast_property->values[0] = 0; + intel_sdvo_connector->contrast_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->contrast_property, - sdvo_priv->cur_contrast); + intel_sdvo_connector->contrast_property, + intel_sdvo_connector->cur_contrast); DRM_DEBUG_KMS("contrast: max %d, " "default %d, current %d\n", data_value[0], data_value[1], response); } if (sdvo_data.hue) { - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_MAX_HUE, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &data_value, 4); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO Max hue\n"); return; } - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_HUE, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &response, 2); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO get hue\n"); return; } - sdvo_priv->max_hue = data_value[0]; - sdvo_priv->cur_hue = response; - sdvo_priv->hue_property = + intel_sdvo_connector->max_hue = data_value[0]; + intel_sdvo_connector->cur_hue = response; + intel_sdvo_connector->hue_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "hue", 2); - sdvo_priv->hue_property->values[0] = 0; - sdvo_priv->hue_property->values[1] = + intel_sdvo_connector->hue_property->values[0] = 0; + intel_sdvo_connector->hue_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->hue_property, - sdvo_priv->cur_hue); + intel_sdvo_connector->hue_property, + intel_sdvo_connector->cur_hue); DRM_DEBUG_KMS("hue: max %d, default %d, current %d\n", data_value[0], data_value[1], response); } } - if (IS_TV(sdvo_priv) || IS_LVDS(sdvo_priv)) { + if (IS_TV(intel_sdvo_connector) || IS_LVDS(intel_sdvo_connector)) { if (sdvo_data.brightness) { - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_MAX_BRIGHTNESS, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &data_value, 4); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO Max bright\n"); return; } - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_BRIGHTNESS, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &response, 2); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO get brigh\n"); return; } - sdvo_priv->max_brightness = data_value[0]; - sdvo_priv->cur_brightness = response; - sdvo_priv->brightness_property = + intel_sdvo_connector->max_brightness = data_value[0]; + intel_sdvo_connector->cur_brightness = response; + intel_sdvo_connector->brightness_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "brightness", 2); - sdvo_priv->brightness_property->values[0] = 0; - sdvo_priv->brightness_property->values[1] = + intel_sdvo_connector->brightness_property->values[0] = 0; + intel_sdvo_connector->brightness_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->brightness_property, - sdvo_priv->cur_brightness); + intel_sdvo_connector->brightness_property, + intel_sdvo_connector->cur_brightness); DRM_DEBUG_KMS("brightness: max %d, " "default %d, current %d\n", data_value[0], data_value[1], response); @@ -2760,20 +2730,18 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_encoder *intel_encoder; - struct intel_sdvo_priv *sdvo_priv; + struct intel_sdvo *intel_sdvo; u8 ch[0x40]; int i; u32 i2c_reg, ddc_reg, analog_ddc_reg; - intel_encoder = kcalloc(sizeof(struct intel_encoder)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL); - if (!intel_encoder) { + intel_sdvo = kzalloc(sizeof(struct intel_sdvo), GFP_KERNEL); + if (!intel_sdvo) return false; - } - sdvo_priv = (struct intel_sdvo_priv *)(intel_encoder + 1); - sdvo_priv->sdvo_reg = sdvo_reg; + intel_sdvo->sdvo_reg = sdvo_reg; - intel_encoder->dev_priv = sdvo_priv; + intel_encoder = &intel_sdvo->base; intel_encoder->type = INTEL_OUTPUT_SDVO; if (HAS_PCH_SPLIT(dev)) { @@ -2795,14 +2763,14 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) if (!intel_encoder->i2c_bus) goto err_inteloutput; - sdvo_priv->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg); + intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg); /* Save the bit-banging i2c functionality for use by the DDC wrapper */ intel_sdvo_i2c_bit_algo.functionality = intel_encoder->i2c_bus->algo->functionality; /* Read the regs to test if we can talk to the device */ for (i = 0; i < 0x40; i++) { - if (!intel_sdvo_read_byte(intel_encoder, i, &ch[i])) { + if (!intel_sdvo_read_byte(intel_sdvo, i, &ch[i])) { DRM_DEBUG_KMS("No SDVO device found on SDVO%c\n", IS_SDVOB(sdvo_reg) ? 'B' : 'C'); goto err_i2c; @@ -2812,12 +2780,12 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) /* setup the DDC bus. */ if (IS_SDVOB(sdvo_reg)) { intel_encoder->ddc_bus = intel_i2c_create(dev, ddc_reg, "SDVOB DDC BUS"); - sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, analog_ddc_reg, + intel_sdvo->analog_ddc_bus = intel_i2c_create(dev, analog_ddc_reg, "SDVOB/VGA DDC BUS"); dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS; } else { intel_encoder->ddc_bus = intel_i2c_create(dev, ddc_reg, "SDVOC DDC BUS"); - sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, analog_ddc_reg, + intel_sdvo->analog_ddc_bus = intel_i2c_create(dev, analog_ddc_reg, "SDVOC/VGA DDC BUS"); dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS; } @@ -2833,53 +2801,53 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) drm_encoder_helper_add(&intel_encoder->enc, &intel_sdvo_helper_funcs); /* In default case sdvo lvds is false */ - intel_sdvo_get_capabilities(intel_encoder, &sdvo_priv->caps); + intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps); - if (intel_sdvo_output_setup(intel_encoder, - sdvo_priv->caps.output_flags) != true) { + if (intel_sdvo_output_setup(intel_sdvo, + intel_sdvo->caps.output_flags) != true) { DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n", IS_SDVOB(sdvo_reg) ? 'B' : 'C'); goto err_i2c; } - intel_sdvo_select_ddc_bus(dev_priv, sdvo_priv, sdvo_reg); + intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg); /* Set the input timing to the screen. Assume always input 0. */ - intel_sdvo_set_target_input(intel_encoder, true, false); + intel_sdvo_set_target_input(intel_sdvo, true, false); - intel_sdvo_get_input_pixel_clock_range(intel_encoder, - &sdvo_priv->pixel_clock_min, - &sdvo_priv->pixel_clock_max); + intel_sdvo_get_input_pixel_clock_range(intel_sdvo, + &intel_sdvo->pixel_clock_min, + &intel_sdvo->pixel_clock_max); DRM_DEBUG_KMS("%s device VID/DID: %02X:%02X.%02X, " "clock range %dMHz - %dMHz, " "input 1: %c, input 2: %c, " "output 1: %c, output 2: %c\n", - SDVO_NAME(sdvo_priv), - sdvo_priv->caps.vendor_id, sdvo_priv->caps.device_id, - sdvo_priv->caps.device_rev_id, - sdvo_priv->pixel_clock_min / 1000, - sdvo_priv->pixel_clock_max / 1000, - (sdvo_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N', - (sdvo_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N', + SDVO_NAME(intel_sdvo), + intel_sdvo->caps.vendor_id, intel_sdvo->caps.device_id, + intel_sdvo->caps.device_rev_id, + intel_sdvo->pixel_clock_min / 1000, + intel_sdvo->pixel_clock_max / 1000, + (intel_sdvo->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N', + (intel_sdvo->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N', /* check currently supported outputs */ - sdvo_priv->caps.output_flags & + intel_sdvo->caps.output_flags & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N', - sdvo_priv->caps.output_flags & + intel_sdvo->caps.output_flags & (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N'); return true; err_i2c: - if (sdvo_priv->analog_ddc_bus != NULL) - intel_i2c_destroy(sdvo_priv->analog_ddc_bus); + if (intel_sdvo->analog_ddc_bus != NULL) + intel_i2c_destroy(intel_sdvo->analog_ddc_bus); if (intel_encoder->ddc_bus != NULL) intel_i2c_destroy(intel_encoder->ddc_bus); if (intel_encoder->i2c_bus != NULL) intel_i2c_destroy(intel_encoder->i2c_bus); err_inteloutput: - kfree(intel_encoder); + kfree(intel_sdvo); return false; } diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index cc3726a..1bd6e87 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -44,7 +44,9 @@ enum tv_margin { }; /** Private structure for the integrated TV support */ -struct intel_tv_priv { +struct intel_tv { + struct intel_encoder base; + int type; char *tv_format; int margin[4]; @@ -896,6 +898,11 @@ static const struct tv_mode tv_modes[] = { }, }; +static struct intel_tv *enc_to_intel_tv(struct drm_encoder *encoder) +{ + return container_of(enc_to_intel_encoder(encoder), struct intel_tv, base); +} + static void intel_tv_dpms(struct drm_encoder *encoder, int mode) { @@ -929,19 +936,17 @@ intel_tv_mode_lookup (char *tv_format) } static const struct tv_mode * -intel_tv_mode_find (struct intel_encoder *intel_encoder) +intel_tv_mode_find (struct intel_tv *intel_tv) { - struct intel_tv_priv *tv_priv = intel_encoder->dev_priv; - - return intel_tv_mode_lookup(tv_priv->tv_format); + return intel_tv_mode_lookup(intel_tv->tv_format); } static enum drm_mode_status intel_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - const struct tv_mode *tv_mode = intel_tv_mode_find(intel_encoder); + struct intel_tv *intel_tv = enc_to_intel_tv(encoder); + const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); /* Ensure TV refresh is close to desired refresh */ if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode) * 1000) @@ -957,8 +962,8 @@ intel_tv_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, { struct drm_device *dev = encoder->dev; struct drm_mode_config *drm_config = &dev->mode_config; - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - const struct tv_mode *tv_mode = intel_tv_mode_find (intel_encoder); + struct intel_tv *intel_tv = enc_to_intel_tv(encoder); + const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); struct drm_encoder *other_encoder; if (!tv_mode) @@ -983,9 +988,8 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = encoder->crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_tv_priv *tv_priv = intel_encoder->dev_priv; - const struct tv_mode *tv_mode = intel_tv_mode_find(intel_encoder); + struct intel_tv *intel_tv = enc_to_intel_tv(encoder); + const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); u32 tv_ctl; u32 hctl1, hctl2, hctl3; u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7; @@ -1001,7 +1005,7 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, tv_ctl = I915_READ(TV_CTL); tv_ctl &= TV_CTL_SAVE; - switch (tv_priv->type) { + switch (intel_tv->type) { default: case DRM_MODE_CONNECTOR_Unknown: case DRM_MODE_CONNECTOR_Composite: @@ -1168,12 +1172,12 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, else ysize = 2*tv_mode->nbr_end + 1; - xpos += tv_priv->margin[TV_MARGIN_LEFT]; - ypos += tv_priv->margin[TV_MARGIN_TOP]; - xsize -= (tv_priv->margin[TV_MARGIN_LEFT] + - tv_priv->margin[TV_MARGIN_RIGHT]); - ysize -= (tv_priv->margin[TV_MARGIN_TOP] + - tv_priv->margin[TV_MARGIN_BOTTOM]); + xpos += intel_tv->margin[TV_MARGIN_LEFT]; + ypos += intel_tv->margin[TV_MARGIN_TOP]; + xsize -= (intel_tv->margin[TV_MARGIN_LEFT] + + intel_tv->margin[TV_MARGIN_RIGHT]); + ysize -= (intel_tv->margin[TV_MARGIN_TOP] + + intel_tv->margin[TV_MARGIN_BOTTOM]); I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos); I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize); @@ -1222,9 +1226,9 @@ static const struct drm_display_mode reported_modes[] = { * \return false if TV is disconnected. */ static int -intel_tv_detect_type (struct drm_crtc *crtc, struct intel_encoder *intel_encoder) +intel_tv_detect_type (struct intel_tv *intel_tv) { - struct drm_encoder *encoder = &intel_encoder->enc; + struct drm_encoder *encoder = &intel_tv->base.enc; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; unsigned long irqflags; @@ -1304,12 +1308,11 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct intel_encoder *intel_encoder static void intel_tv_find_better_format(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_tv_priv *tv_priv = intel_encoder->dev_priv; - const struct tv_mode *tv_mode = intel_tv_mode_find(intel_encoder); + struct intel_tv *intel_tv = enc_to_intel_tv(encoder); + const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); int i; - if ((tv_priv->type == DRM_MODE_CONNECTOR_Component) == + if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) == tv_mode->component_only) return; @@ -1317,12 +1320,12 @@ static void intel_tv_find_better_format(struct drm_connector *connector) for (i = 0; i < sizeof(tv_modes) / sizeof(*tv_modes); i++) { tv_mode = tv_modes + i; - if ((tv_priv->type == DRM_MODE_CONNECTOR_Component) == + if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) == tv_mode->component_only) break; } - tv_priv->tv_format = tv_mode->name; + intel_tv->tv_format = tv_mode->name; drm_connector_property_set_value(connector, connector->dev->mode_config.tv_mode_property, i); } @@ -1336,31 +1339,31 @@ static void intel_tv_find_better_format(struct drm_connector *connector) static enum drm_connector_status intel_tv_detect(struct drm_connector *connector) { - struct drm_crtc *crtc; struct drm_display_mode mode; struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_tv_priv *tv_priv = intel_encoder->dev_priv; - int dpms_mode; - int type = tv_priv->type; + struct intel_tv *intel_tv = enc_to_intel_tv(encoder); + int type; mode = reported_modes[0]; drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V); if (encoder->crtc && encoder->crtc->enabled) { - type = intel_tv_detect_type(encoder->crtc, intel_encoder); + type = intel_tv_detect_type(intel_tv); } else { - crtc = intel_get_load_detect_pipe(intel_encoder, connector, + struct drm_crtc *crtc; + int dpms_mode; + + crtc = intel_get_load_detect_pipe(&intel_tv->base, connector, &mode, &dpms_mode); if (crtc) { - type = intel_tv_detect_type(crtc, intel_encoder); - intel_release_load_detect_pipe(intel_encoder, connector, + type = intel_tv_detect_type(intel_tv); + intel_release_load_detect_pipe(&intel_tv->base, connector, dpms_mode); } else type = -1; } - tv_priv->type = type; + intel_tv->type = type; if (type < 0) return connector_status_disconnected; @@ -1391,8 +1394,8 @@ intel_tv_chose_preferred_modes(struct drm_connector *connector, struct drm_display_mode *mode_ptr) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - const struct tv_mode *tv_mode = intel_tv_mode_find(intel_encoder); + struct intel_tv *intel_tv = enc_to_intel_tv(encoder); + const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480) mode_ptr->type |= DRM_MODE_TYPE_PREFERRED; @@ -1417,8 +1420,8 @@ intel_tv_get_modes(struct drm_connector *connector) { struct drm_display_mode *mode_ptr; struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - const struct tv_mode *tv_mode = intel_tv_mode_find(intel_encoder); + struct intel_tv *intel_tv = enc_to_intel_tv(encoder); + const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); int j, count = 0; u64 tmp; @@ -1483,8 +1486,7 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop { struct drm_device *dev = connector->dev; struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_tv_priv *tv_priv = intel_encoder->dev_priv; + struct intel_tv *intel_tv = enc_to_intel_tv(encoder); struct drm_crtc *crtc = encoder->crtc; int ret = 0; bool changed = false; @@ -1494,30 +1496,30 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop goto out; if (property == dev->mode_config.tv_left_margin_property && - tv_priv->margin[TV_MARGIN_LEFT] != val) { - tv_priv->margin[TV_MARGIN_LEFT] = val; + intel_tv->margin[TV_MARGIN_LEFT] != val) { + intel_tv->margin[TV_MARGIN_LEFT] = val; changed = true; } else if (property == dev->mode_config.tv_right_margin_property && - tv_priv->margin[TV_MARGIN_RIGHT] != val) { - tv_priv->margin[TV_MARGIN_RIGHT] = val; + intel_tv->margin[TV_MARGIN_RIGHT] != val) { + intel_tv->margin[TV_MARGIN_RIGHT] = val; changed = true; } else if (property == dev->mode_config.tv_top_margin_property && - tv_priv->margin[TV_MARGIN_TOP] != val) { - tv_priv->margin[TV_MARGIN_TOP] = val; + intel_tv->margin[TV_MARGIN_TOP] != val) { + intel_tv->margin[TV_MARGIN_TOP] = val; changed = true; } else if (property == dev->mode_config.tv_bottom_margin_property && - tv_priv->margin[TV_MARGIN_BOTTOM] != val) { - tv_priv->margin[TV_MARGIN_BOTTOM] = val; + intel_tv->margin[TV_MARGIN_BOTTOM] != val) { + intel_tv->margin[TV_MARGIN_BOTTOM] = val; changed = true; } else if (property == dev->mode_config.tv_mode_property) { if (val >= ARRAY_SIZE(tv_modes)) { ret = -EINVAL; goto out; } - if (!strcmp(tv_priv->tv_format, tv_modes[val].name)) + if (!strcmp(intel_tv->tv_format, tv_modes[val].name)) goto out; - tv_priv->tv_format = tv_modes[val].name; + intel_tv->tv_format = tv_modes[val].name; changed = true; } else { ret = -EINVAL; @@ -1553,16 +1555,8 @@ static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = .best_encoder = intel_attached_encoder, }; -static void intel_tv_enc_destroy(struct drm_encoder *encoder) -{ - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - - drm_encoder_cleanup(encoder); - kfree(intel_encoder); -} - static const struct drm_encoder_funcs intel_tv_enc_funcs = { - .destroy = intel_tv_enc_destroy, + .destroy = intel_encoder_destroy, }; /* @@ -1606,9 +1600,9 @@ intel_tv_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_connector *connector; + struct intel_tv *intel_tv; struct intel_encoder *intel_encoder; struct intel_connector *intel_connector; - struct intel_tv_priv *tv_priv; u32 tv_dac_on, tv_dac_off, save_tv_dac; char **tv_format_names; int i, initial_mode = 0; @@ -1647,18 +1641,18 @@ intel_tv_init(struct drm_device *dev) (tv_dac_off & TVDAC_STATE_CHG_EN) != 0) return; - intel_encoder = kzalloc(sizeof(struct intel_encoder) + - sizeof(struct intel_tv_priv), GFP_KERNEL); - if (!intel_encoder) { + intel_tv = kzalloc(sizeof(struct intel_tv), GFP_KERNEL); + if (!intel_tv) { return; } intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); if (!intel_connector) { - kfree(intel_encoder); + kfree(intel_tv); return; } + intel_encoder = &intel_tv->base; connector = &intel_connector->base; drm_connector_init(dev, connector, &intel_tv_connector_funcs, @@ -1668,22 +1662,20 @@ intel_tv_init(struct drm_device *dev) DRM_MODE_ENCODER_TVDAC); drm_mode_connector_attach_encoder(&intel_connector->base, &intel_encoder->enc); - tv_priv = (struct intel_tv_priv *)(intel_encoder + 1); intel_encoder->type = INTEL_OUTPUT_TVOUT; intel_encoder->crtc_mask = (1 << 0) | (1 << 1); intel_encoder->clone_mask = (1 << INTEL_TV_CLONE_BIT); intel_encoder->enc.possible_crtcs = ((1 << 0) | (1 << 1)); intel_encoder->enc.possible_clones = (1 << INTEL_OUTPUT_TVOUT); - intel_encoder->dev_priv = tv_priv; - tv_priv->type = DRM_MODE_CONNECTOR_Unknown; + intel_tv->type = DRM_MODE_CONNECTOR_Unknown; /* BIOS margin values */ - tv_priv->margin[TV_MARGIN_LEFT] = 54; - tv_priv->margin[TV_MARGIN_TOP] = 36; - tv_priv->margin[TV_MARGIN_RIGHT] = 46; - tv_priv->margin[TV_MARGIN_BOTTOM] = 37; + intel_tv->margin[TV_MARGIN_LEFT] = 54; + intel_tv->margin[TV_MARGIN_TOP] = 36; + intel_tv->margin[TV_MARGIN_RIGHT] = 46; + intel_tv->margin[TV_MARGIN_BOTTOM] = 37; - tv_priv->tv_format = kstrdup(tv_modes[initial_mode].name, GFP_KERNEL); + intel_tv->tv_format = kstrdup(tv_modes[initial_mode].name, GFP_KERNEL); drm_encoder_helper_add(&intel_encoder->enc, &intel_tv_helper_funcs); drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs); @@ -1703,16 +1695,16 @@ intel_tv_init(struct drm_device *dev) initial_mode); drm_connector_attach_property(connector, dev->mode_config.tv_left_margin_property, - tv_priv->margin[TV_MARGIN_LEFT]); + intel_tv->margin[TV_MARGIN_LEFT]); drm_connector_attach_property(connector, dev->mode_config.tv_top_margin_property, - tv_priv->margin[TV_MARGIN_TOP]); + intel_tv->margin[TV_MARGIN_TOP]); drm_connector_attach_property(connector, dev->mode_config.tv_right_margin_property, - tv_priv->margin[TV_MARGIN_RIGHT]); + intel_tv->margin[TV_MARGIN_RIGHT]); drm_connector_attach_property(connector, dev->mode_config.tv_bottom_margin_property, - tv_priv->margin[TV_MARGIN_BOTTOM]); + intel_tv->margin[TV_MARGIN_BOTTOM]); out: drm_sysfs_connector_add(connector); } -- cgit v0.10.2 From 615fb93f6d99cce2ab36dcf09986e321e17c356f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 13:50:24 +0100 Subject: drm/i915: Subclass intel_connector. Make the code that tiny bit clearer by reducing the pointer dance. 2 files changed, 130 insertions(+), 147 deletions(-) Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 520b22c..1075d43 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -109,7 +109,6 @@ struct intel_encoder { struct intel_connector { struct drm_connector base; - void *dev_priv; }; struct intel_crtc; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 2fc9da4..dca1235 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -134,6 +134,8 @@ struct intel_sdvo { }; struct intel_sdvo_connector { + struct intel_connector base; + /* Mark the type of connector */ uint16_t output_flag; @@ -180,6 +182,11 @@ static struct intel_sdvo *enc_to_intel_sdvo(struct drm_encoder *encoder) return container_of(enc_to_intel_encoder(encoder), struct intel_sdvo, base); } +static struct intel_sdvo_connector *to_intel_sdvo_connector(struct drm_connector *connector) +{ + return container_of(to_intel_connector(connector), struct intel_sdvo_connector, base); +} + static bool intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags); static void @@ -1502,8 +1509,7 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); - struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; + struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); enum drm_connector_status status = connector_status_connected; struct edid *edid = NULL; @@ -1543,7 +1549,7 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) if (edid != NULL) { bool is_digital = !!(edid->input & DRM_EDID_INPUT_DIGITAL); - bool need_digital = !!(sdvo_connector->output_flag & SDVO_TMDS_MASK); + bool need_digital = !!(intel_sdvo_connector->output_flag & SDVO_TMDS_MASK); /* DDC bus is shared, match EDID to connector type */ if (is_digital && need_digital) @@ -1566,8 +1572,7 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect u8 status; struct drm_encoder *encoder = intel_attached_encoder(connector); struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); - struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; + struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); enum drm_connector_status ret; intel_sdvo_write_cmd(intel_sdvo, @@ -1588,7 +1593,7 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect intel_sdvo->attached_output = response; - if ((sdvo_connector->output_flag & response) == 0) + if ((intel_sdvo_connector->output_flag & response) == 0) ret = connector_status_disconnected; else if (response & SDVO_TMDS_MASK) ret = intel_sdvo_hdmi_sink_detect(connector); @@ -1784,12 +1789,11 @@ end: static int intel_sdvo_get_modes(struct drm_connector *connector) { - struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; + struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); - if (IS_TV(sdvo_connector)) + if (IS_TV(intel_sdvo_connector)) intel_sdvo_get_tv_modes(connector); - else if (IS_LVDS(sdvo_connector)) + else if (IS_LVDS(intel_sdvo_connector)) intel_sdvo_get_lvds_modes(connector); else intel_sdvo_get_ddc_modes(connector); @@ -1802,48 +1806,46 @@ static int intel_sdvo_get_modes(struct drm_connector *connector) static void intel_sdvo_destroy_enhance_property(struct drm_connector *connector) { - struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_connector *intel_sdvo = intel_connector->dev_priv; + struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); struct drm_device *dev = connector->dev; - if (IS_TV(intel_sdvo)) { - if (intel_sdvo->left_property) - drm_property_destroy(dev, intel_sdvo->left_property); - if (intel_sdvo->right_property) - drm_property_destroy(dev, intel_sdvo->right_property); - if (intel_sdvo->top_property) - drm_property_destroy(dev, intel_sdvo->top_property); - if (intel_sdvo->bottom_property) - drm_property_destroy(dev, intel_sdvo->bottom_property); - if (intel_sdvo->hpos_property) - drm_property_destroy(dev, intel_sdvo->hpos_property); - if (intel_sdvo->vpos_property) - drm_property_destroy(dev, intel_sdvo->vpos_property); - if (intel_sdvo->saturation_property) + if (IS_TV(intel_sdvo_connector)) { + if (intel_sdvo_connector->left_property) + drm_property_destroy(dev, intel_sdvo_connector->left_property); + if (intel_sdvo_connector->right_property) + drm_property_destroy(dev, intel_sdvo_connector->right_property); + if (intel_sdvo_connector->top_property) + drm_property_destroy(dev, intel_sdvo_connector->top_property); + if (intel_sdvo_connector->bottom_property) + drm_property_destroy(dev, intel_sdvo_connector->bottom_property); + if (intel_sdvo_connector->hpos_property) + drm_property_destroy(dev, intel_sdvo_connector->hpos_property); + if (intel_sdvo_connector->vpos_property) + drm_property_destroy(dev, intel_sdvo_connector->vpos_property); + if (intel_sdvo_connector->saturation_property) drm_property_destroy(dev, - intel_sdvo->saturation_property); - if (intel_sdvo->contrast_property) + intel_sdvo_connector->saturation_property); + if (intel_sdvo_connector->contrast_property) drm_property_destroy(dev, - intel_sdvo->contrast_property); - if (intel_sdvo->hue_property) - drm_property_destroy(dev, intel_sdvo->hue_property); + intel_sdvo_connector->contrast_property); + if (intel_sdvo_connector->hue_property) + drm_property_destroy(dev, intel_sdvo_connector->hue_property); } - if (IS_TV(intel_sdvo) || IS_LVDS(intel_sdvo)) { - if (intel_sdvo->brightness_property) + if (IS_TV(intel_sdvo_connector) || IS_LVDS(intel_sdvo_connector)) { + if (intel_sdvo_connector->brightness_property) drm_property_destroy(dev, - intel_sdvo->brightness_property); + intel_sdvo_connector->brightness_property); } return; } static void intel_sdvo_destroy(struct drm_connector *connector) { - struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; + struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); - if (sdvo_connector->tv_format_property) + if (intel_sdvo_connector->tv_format_property) drm_property_destroy(connector->dev, - sdvo_connector->tv_format_property); + intel_sdvo_connector->tv_format_property); intel_sdvo_destroy_enhance_property(connector); drm_sysfs_connector_remove(connector); @@ -1858,8 +1860,7 @@ intel_sdvo_set_property(struct drm_connector *connector, { struct drm_encoder *encoder = intel_attached_encoder(connector); struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); - struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; + struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); struct drm_crtc *crtc = encoder->crtc; int ret = 0; bool changed = false; @@ -1870,101 +1871,101 @@ intel_sdvo_set_property(struct drm_connector *connector, if (ret < 0) goto out; - if (property == sdvo_connector->tv_format_property) { + if (property == intel_sdvo_connector->tv_format_property) { if (val >= TV_FORMAT_NUM) { ret = -EINVAL; goto out; } if (intel_sdvo->tv_format_name == - sdvo_connector->tv_format_supported[val]) + intel_sdvo_connector->tv_format_supported[val]) goto out; - intel_sdvo->tv_format_name = sdvo_connector->tv_format_supported[val]; + intel_sdvo->tv_format_name = intel_sdvo_connector->tv_format_supported[val]; changed = true; } - if (IS_TV(sdvo_connector) || IS_LVDS(sdvo_connector)) { + if (IS_TV(intel_sdvo_connector) || IS_LVDS(intel_sdvo_connector)) { cmd = 0; temp_value = val; - if (sdvo_connector->left_property == property) { + if (intel_sdvo_connector->left_property == property) { drm_connector_property_set_value(connector, - sdvo_connector->right_property, val); - if (sdvo_connector->left_margin == temp_value) + intel_sdvo_connector->right_property, val); + if (intel_sdvo_connector->left_margin == temp_value) goto out; - sdvo_connector->left_margin = temp_value; - sdvo_connector->right_margin = temp_value; - temp_value = sdvo_connector->max_hscan - - sdvo_connector->left_margin; + intel_sdvo_connector->left_margin = temp_value; + intel_sdvo_connector->right_margin = temp_value; + temp_value = intel_sdvo_connector->max_hscan - + intel_sdvo_connector->left_margin; cmd = SDVO_CMD_SET_OVERSCAN_H; - } else if (sdvo_connector->right_property == property) { + } else if (intel_sdvo_connector->right_property == property) { drm_connector_property_set_value(connector, - sdvo_connector->left_property, val); - if (sdvo_connector->right_margin == temp_value) + intel_sdvo_connector->left_property, val); + if (intel_sdvo_connector->right_margin == temp_value) goto out; - sdvo_connector->left_margin = temp_value; - sdvo_connector->right_margin = temp_value; - temp_value = sdvo_connector->max_hscan - - sdvo_connector->left_margin; + intel_sdvo_connector->left_margin = temp_value; + intel_sdvo_connector->right_margin = temp_value; + temp_value = intel_sdvo_connector->max_hscan - + intel_sdvo_connector->left_margin; cmd = SDVO_CMD_SET_OVERSCAN_H; - } else if (sdvo_connector->top_property == property) { + } else if (intel_sdvo_connector->top_property == property) { drm_connector_property_set_value(connector, - sdvo_connector->bottom_property, val); - if (sdvo_connector->top_margin == temp_value) + intel_sdvo_connector->bottom_property, val); + if (intel_sdvo_connector->top_margin == temp_value) goto out; - sdvo_connector->top_margin = temp_value; - sdvo_connector->bottom_margin = temp_value; - temp_value = sdvo_connector->max_vscan - - sdvo_connector->top_margin; + intel_sdvo_connector->top_margin = temp_value; + intel_sdvo_connector->bottom_margin = temp_value; + temp_value = intel_sdvo_connector->max_vscan - + intel_sdvo_connector->top_margin; cmd = SDVO_CMD_SET_OVERSCAN_V; - } else if (sdvo_connector->bottom_property == property) { + } else if (intel_sdvo_connector->bottom_property == property) { drm_connector_property_set_value(connector, - sdvo_connector->top_property, val); - if (sdvo_connector->bottom_margin == temp_value) + intel_sdvo_connector->top_property, val); + if (intel_sdvo_connector->bottom_margin == temp_value) goto out; - sdvo_connector->top_margin = temp_value; - sdvo_connector->bottom_margin = temp_value; - temp_value = sdvo_connector->max_vscan - - sdvo_connector->top_margin; + intel_sdvo_connector->top_margin = temp_value; + intel_sdvo_connector->bottom_margin = temp_value; + temp_value = intel_sdvo_connector->max_vscan - + intel_sdvo_connector->top_margin; cmd = SDVO_CMD_SET_OVERSCAN_V; - } else if (sdvo_connector->hpos_property == property) { - if (sdvo_connector->cur_hpos == temp_value) + } else if (intel_sdvo_connector->hpos_property == property) { + if (intel_sdvo_connector->cur_hpos == temp_value) goto out; cmd = SDVO_CMD_SET_POSITION_H; - sdvo_connector->cur_hpos = temp_value; - } else if (sdvo_connector->vpos_property == property) { - if (sdvo_connector->cur_vpos == temp_value) + intel_sdvo_connector->cur_hpos = temp_value; + } else if (intel_sdvo_connector->vpos_property == property) { + if (intel_sdvo_connector->cur_vpos == temp_value) goto out; cmd = SDVO_CMD_SET_POSITION_V; - sdvo_connector->cur_vpos = temp_value; - } else if (sdvo_connector->saturation_property == property) { - if (sdvo_connector->cur_saturation == temp_value) + intel_sdvo_connector->cur_vpos = temp_value; + } else if (intel_sdvo_connector->saturation_property == property) { + if (intel_sdvo_connector->cur_saturation == temp_value) goto out; cmd = SDVO_CMD_SET_SATURATION; - sdvo_connector->cur_saturation = temp_value; - } else if (sdvo_connector->contrast_property == property) { - if (sdvo_connector->cur_contrast == temp_value) + intel_sdvo_connector->cur_saturation = temp_value; + } else if (intel_sdvo_connector->contrast_property == property) { + if (intel_sdvo_connector->cur_contrast == temp_value) goto out; cmd = SDVO_CMD_SET_CONTRAST; - sdvo_connector->cur_contrast = temp_value; - } else if (sdvo_connector->hue_property == property) { - if (sdvo_connector->cur_hue == temp_value) + intel_sdvo_connector->cur_contrast = temp_value; + } else if (intel_sdvo_connector->hue_property == property) { + if (intel_sdvo_connector->cur_hue == temp_value) goto out; cmd = SDVO_CMD_SET_HUE; - sdvo_connector->cur_hue = temp_value; - } else if (sdvo_connector->brightness_property == property) { - if (sdvo_connector->cur_brightness == temp_value) + intel_sdvo_connector->cur_hue = temp_value; + } else if (intel_sdvo_connector->brightness_property == property) { + if (intel_sdvo_connector->cur_brightness == temp_value) goto out; cmd = SDVO_CMD_SET_BRIGHTNESS; - sdvo_connector->cur_brightness = temp_value; + intel_sdvo_connector->cur_brightness = temp_value; } if (cmd) { intel_sdvo_write_cmd(intel_sdvo, cmd, &temp_value, 2); @@ -2139,24 +2140,6 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg) return 0x72; } -static bool -intel_sdvo_connector_alloc (struct intel_connector **ret) -{ - struct intel_connector *intel_connector; - struct intel_sdvo_connector *sdvo_connector; - - *ret = kzalloc(sizeof(*intel_connector) + - sizeof(*sdvo_connector), GFP_KERNEL); - if (!*ret) - return false; - - intel_connector = *ret; - sdvo_connector = (struct intel_sdvo_connector *)(intel_connector + 1); - intel_connector->dev_priv = sdvo_connector; - - return true; -} - static void intel_sdvo_connector_create (struct drm_encoder *encoder, struct drm_connector *connector) @@ -2180,21 +2163,21 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) struct drm_encoder *encoder = &intel_sdvo->base.enc; struct drm_connector *connector; struct intel_connector *intel_connector; - struct intel_sdvo_connector *sdvo_connector; + struct intel_sdvo_connector *intel_sdvo_connector; - if (!intel_sdvo_connector_alloc(&intel_connector)) + intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL); + if (!intel_sdvo_connector) return false; - sdvo_connector = intel_connector->dev_priv; - if (device == 0) { intel_sdvo->controlled_output |= SDVO_OUTPUT_TMDS0; - sdvo_connector->output_flag = SDVO_OUTPUT_TMDS0; + intel_sdvo_connector->output_flag = SDVO_OUTPUT_TMDS0; } else if (device == 1) { intel_sdvo->controlled_output |= SDVO_OUTPUT_TMDS1; - sdvo_connector->output_flag = SDVO_OUTPUT_TMDS1; + intel_sdvo_connector->output_flag = SDVO_OUTPUT_TMDS1; } + intel_connector = &intel_sdvo_connector->base; connector = &intel_connector->base; connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; encoder->encoder_type = DRM_MODE_ENCODER_TMDS; @@ -2223,18 +2206,19 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type) struct drm_encoder *encoder = &intel_sdvo->base.enc; struct drm_connector *connector; struct intel_connector *intel_connector; - struct intel_sdvo_connector *sdvo_connector; + struct intel_sdvo_connector *intel_sdvo_connector; - if (!intel_sdvo_connector_alloc(&intel_connector)) - return false; + intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL); + if (!intel_sdvo_connector) + return false; + intel_connector = &intel_sdvo_connector->base; connector = &intel_connector->base; encoder->encoder_type = DRM_MODE_ENCODER_TVDAC; connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO; - sdvo_connector = intel_connector->dev_priv; intel_sdvo->controlled_output |= type; - sdvo_connector->output_flag = type; + intel_sdvo_connector->output_flag = type; intel_sdvo->is_tv = true; intel_sdvo->base.needs_tv_clock = true; @@ -2255,23 +2239,24 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device) struct drm_encoder *encoder = &intel_sdvo->base.enc; struct drm_connector *connector; struct intel_connector *intel_connector; - struct intel_sdvo_connector *sdvo_connector; + struct intel_sdvo_connector *intel_sdvo_connector; - if (!intel_sdvo_connector_alloc(&intel_connector)) - return false; + intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL); + if (!intel_sdvo_connector) + return false; + intel_connector = &intel_sdvo_connector->base; connector = &intel_connector->base; connector->polled = DRM_CONNECTOR_POLL_CONNECT; encoder->encoder_type = DRM_MODE_ENCODER_DAC; connector->connector_type = DRM_MODE_CONNECTOR_VGA; - sdvo_connector = intel_connector->dev_priv; if (device == 0) { intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB0; - sdvo_connector->output_flag = SDVO_OUTPUT_RGB0; + intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB0; } else if (device == 1) { intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB1; - sdvo_connector->output_flag = SDVO_OUTPUT_RGB1; + intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1; } intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) | @@ -2287,24 +2272,25 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) struct drm_encoder *encoder = &intel_sdvo->base.enc; struct drm_connector *connector; struct intel_connector *intel_connector; - struct intel_sdvo_connector *sdvo_connector; + struct intel_sdvo_connector *intel_sdvo_connector; - if (!intel_sdvo_connector_alloc(&intel_connector)) - return false; + intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL); + if (!intel_sdvo_connector) + return false; - connector = &intel_connector->base; + intel_connector = &intel_sdvo_connector->base; + connector = &intel_connector->base; encoder->encoder_type = DRM_MODE_ENCODER_LVDS; connector->connector_type = DRM_MODE_CONNECTOR_LVDS; - sdvo_connector = intel_connector->dev_priv; intel_sdvo->is_lvds = true; if (device == 0) { intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS0; - sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0; + intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0; } else if (device == 1) { intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS1; - sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1; + intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1; } intel_sdvo->base.clone_mask = ((1 << INTEL_ANALOG_CLONE_BIT) | @@ -2376,8 +2362,7 @@ static void intel_sdvo_tv_create_property(struct drm_connector *connector, int t { struct drm_encoder *encoder = intel_attached_encoder(connector); struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); - struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; + struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); struct intel_sdvo_tv_format format; uint32_t format_map, i; uint8_t status; @@ -2397,28 +2382,28 @@ static void intel_sdvo_tv_create_property(struct drm_connector *connector, int t if (format_map == 0) return; - sdvo_connector->format_supported_num = 0; + intel_sdvo_connector->format_supported_num = 0; for (i = 0 ; i < TV_FORMAT_NUM; i++) if (format_map & (1 << i)) { - sdvo_connector->tv_format_supported - [sdvo_connector->format_supported_num++] = + intel_sdvo_connector->tv_format_supported + [intel_sdvo_connector->format_supported_num++] = tv_format_names[i]; } - sdvo_connector->tv_format_property = + intel_sdvo_connector->tv_format_property = drm_property_create( connector->dev, DRM_MODE_PROP_ENUM, - "mode", sdvo_connector->format_supported_num); + "mode", intel_sdvo_connector->format_supported_num); - for (i = 0; i < sdvo_connector->format_supported_num; i++) + for (i = 0; i < intel_sdvo_connector->format_supported_num; i++) drm_property_add_enum( - sdvo_connector->tv_format_property, i, - i, sdvo_connector->tv_format_supported[i]); + intel_sdvo_connector->tv_format_property, i, + i, intel_sdvo_connector->tv_format_supported[i]); - intel_sdvo->tv_format_name = sdvo_connector->tv_format_supported[0]; + intel_sdvo->tv_format_name = intel_sdvo_connector->tv_format_supported[0]; drm_connector_attach_property( - connector, sdvo_connector->tv_format_property, 0); + connector, intel_sdvo_connector->tv_format_property, 0); } @@ -2426,8 +2411,7 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); - struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_connector *intel_sdvo_connector = intel_connector->dev_priv; + struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); struct intel_sdvo_enhancements_reply sdvo_data; struct drm_device *dev = connector->dev; uint8_t status; -- cgit v0.10.2 From 32aad86fe88e7323d4fc5e9e423abcee0d55a03d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 13:50:25 +0100 Subject: drm/i915/sdvo: Propagate errors from reading/writing control bus. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index dca1235..300f110 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -47,6 +47,7 @@ #define IS_TV(c) (c->output_flag & SDVO_TV_MASK) #define IS_LVDS(c) (c->output_flag & SDVO_LVDS_MASK) +#define IS_TV_OR_LVDS(c) (c->output_flag & (SDVO_TV_MASK | SDVO_LVDS_MASK)) static char *tv_format_names[] = { @@ -189,10 +190,13 @@ static struct intel_sdvo_connector *to_intel_sdvo_connector(struct drm_connector static bool intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags); -static void -intel_sdvo_tv_create_property(struct drm_connector *connector, int type); -static void -intel_sdvo_create_enhance_property(struct drm_connector *connector); +static bool +intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *intel_sdvo_connector, + int type); +static bool +intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *intel_sdvo_connector); /** * Writes the SDVOB or SDVOC with the given value, but always writes both @@ -231,13 +235,10 @@ static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val) } } -static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, - u8 *ch) +static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, u8 *ch) { - u8 out_buf[2]; + u8 out_buf[2] = { addr, 0 }; u8 buf[2]; - int ret; - struct i2c_msg msgs[] = { { .addr = intel_sdvo->slave_addr >> 1, @@ -252,9 +253,7 @@ static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, .buf = buf, } }; - - out_buf[0] = addr; - out_buf[1] = 0; + int ret; if ((ret = i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 2)) == 2) { @@ -266,10 +265,9 @@ static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, return false; } -static bool intel_sdvo_write_byte(struct intel_sdvo *intel_sdvo, int addr, - u8 ch) +static bool intel_sdvo_write_byte(struct intel_sdvo *intel_sdvo, int addr, u8 ch) { - u8 out_buf[2]; + u8 out_buf[2] = { addr, ch }; struct i2c_msg msgs[] = { { .addr = intel_sdvo->slave_addr >> 1, @@ -279,14 +277,7 @@ static bool intel_sdvo_write_byte(struct intel_sdvo *intel_sdvo, int addr, } }; - out_buf[0] = addr; - out_buf[1] = ch; - - if (i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 1) == 1) - { - return true; - } - return false; + return i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 1) == 1; } #define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd} @@ -390,7 +381,7 @@ static const struct _sdvo_cmd_name { #define SDVO_NAME(svdo) (IS_SDVOB((svdo)->sdvo_reg) ? "SDVOB" : "SDVOC") static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd, - void *args, int args_len) + const void *args, int args_len) { int i; @@ -411,19 +402,20 @@ static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd, DRM_LOG_KMS("\n"); } -static void intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd, - void *args, int args_len) +static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd, + const void *args, int args_len) { int i; intel_sdvo_debug_write(intel_sdvo, cmd, args, args_len); for (i = 0; i < args_len; i++) { - intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_ARG_0 - i, - ((u8*)args)[i]); + if (!intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_ARG_0 - i, + ((u8*)args)[i])) + return false; } - intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_OPCODE, cmd); + return intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_OPCODE, cmd); } static const char *cmd_status_names[] = { @@ -454,8 +446,8 @@ static void intel_sdvo_debug_response(struct intel_sdvo *intel_sdvo, DRM_LOG_KMS("\n"); } -static u8 intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, - void *response, int response_len) +static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, + void *response, int response_len) { int i; u8 status; @@ -464,24 +456,26 @@ static u8 intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, while (retry--) { /* Read the command response */ for (i = 0; i < response_len; i++) { - intel_sdvo_read_byte(intel_sdvo, - SDVO_I2C_RETURN_0 + i, - &((u8 *)response)[i]); + if (!intel_sdvo_read_byte(intel_sdvo, + SDVO_I2C_RETURN_0 + i, + &((u8 *)response)[i])) + return false; } /* read the return status */ - intel_sdvo_read_byte(intel_sdvo, SDVO_I2C_CMD_STATUS, - &status); + if (!intel_sdvo_read_byte(intel_sdvo, SDVO_I2C_CMD_STATUS, + &status)) + return false; intel_sdvo_debug_response(intel_sdvo, response, response_len, status); if (status != SDVO_CMD_STATUS_PENDING) - return status; + break; mdelay(50); } - return status; + return status == SDVO_CMD_STATUS_SUCCESS; } static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode) @@ -553,23 +547,29 @@ static void intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo, return; } -static bool intel_sdvo_set_target_input(struct intel_sdvo *intel_sdvo, bool target_0, bool target_1) +static bool intel_sdvo_set_value(struct intel_sdvo *intel_sdvo, u8 cmd, const void *data, int len) { - struct intel_sdvo_set_target_input_args targets = {0}; - u8 status; - - if (target_0 && target_1) - return SDVO_CMD_STATUS_NOTSUPP; + if (!intel_sdvo_write_cmd(intel_sdvo, cmd, data, len)) + return false; - if (target_1) - targets.target_1 = 1; + return intel_sdvo_read_response(intel_sdvo, NULL, 0); +} - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_TARGET_INPUT, &targets, - sizeof(targets)); +static bool +intel_sdvo_get_value(struct intel_sdvo *intel_sdvo, u8 cmd, void *value, int len) +{ + if (!intel_sdvo_write_cmd(intel_sdvo, cmd, NULL, 0)) + return false; - status = intel_sdvo_read_response(intel_sdvo, NULL, 0); + return intel_sdvo_read_response(intel_sdvo, value, len); +} - return (status == SDVO_CMD_STATUS_SUCCESS); +static bool intel_sdvo_set_target_input(struct intel_sdvo *intel_sdvo) +{ + struct intel_sdvo_set_target_input_args targets = {0}; + return intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_TARGET_INPUT, + &targets, sizeof(targets)); } /** @@ -581,11 +581,9 @@ static bool intel_sdvo_set_target_input(struct intel_sdvo *intel_sdvo, bool targ static bool intel_sdvo_get_trained_inputs(struct intel_sdvo *intel_sdvo, bool *input_1, bool *input_2) { struct intel_sdvo_get_trained_inputs_response response; - u8 status; - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_TRAINED_INPUTS, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, &response, sizeof(response)); - if (status != SDVO_CMD_STATUS_SUCCESS) + if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_TRAINED_INPUTS, + &response, sizeof(response))) return false; *input_1 = response.input0_trained; @@ -596,18 +594,15 @@ static bool intel_sdvo_get_trained_inputs(struct intel_sdvo *intel_sdvo, bool *i static bool intel_sdvo_set_active_outputs(struct intel_sdvo *intel_sdvo, u16 outputs) { - u8 status; - - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_OUTPUTS, &outputs, - sizeof(outputs)); - status = intel_sdvo_read_response(intel_sdvo, NULL, 0); - return (status == SDVO_CMD_STATUS_SUCCESS); + return intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_ACTIVE_OUTPUTS, + &outputs, sizeof(outputs)); } static bool intel_sdvo_set_encoder_power_state(struct intel_sdvo *intel_sdvo, int mode) { - u8 status, state = SDVO_ENCODER_STATE_ON; + u8 state = SDVO_ENCODER_STATE_ON; switch (mode) { case DRM_MODE_DPMS_ON: @@ -624,11 +619,8 @@ static bool intel_sdvo_set_encoder_power_state(struct intel_sdvo *intel_sdvo, break; } - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ENCODER_POWER_STATE, &state, - sizeof(state)); - status = intel_sdvo_read_response(intel_sdvo, NULL, 0); - - return (status == SDVO_CMD_STATUS_SUCCESS); + return intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_ENCODER_POWER_STATE, &state, sizeof(state)); } static bool intel_sdvo_get_input_pixel_clock_range(struct intel_sdvo *intel_sdvo, @@ -636,51 +628,31 @@ static bool intel_sdvo_get_input_pixel_clock_range(struct intel_sdvo *intel_sdvo int *clock_max) { struct intel_sdvo_pixel_clock_range clocks; - u8 status; - - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE, - NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, &clocks, sizeof(clocks)); - - if (status != SDVO_CMD_STATUS_SUCCESS) + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE, + &clocks, sizeof(clocks))) return false; /* Convert the values from units of 10 kHz to kHz. */ *clock_min = clocks.min * 10; *clock_max = clocks.max * 10; - return true; } static bool intel_sdvo_set_target_output(struct intel_sdvo *intel_sdvo, u16 outputs) { - u8 status; - - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_TARGET_OUTPUT, &outputs, - sizeof(outputs)); - - status = intel_sdvo_read_response(intel_sdvo, NULL, 0); - return (status == SDVO_CMD_STATUS_SUCCESS); + return intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_TARGET_OUTPUT, + &outputs, sizeof(outputs)); } static bool intel_sdvo_set_timing(struct intel_sdvo *intel_sdvo, u8 cmd, struct intel_sdvo_dtd *dtd) { - u8 status; - - intel_sdvo_write_cmd(intel_sdvo, cmd, &dtd->part1, sizeof(dtd->part1)); - status = intel_sdvo_read_response(intel_sdvo, NULL, 0); - if (status != SDVO_CMD_STATUS_SUCCESS) - return false; - - intel_sdvo_write_cmd(intel_sdvo, cmd + 1, &dtd->part2, sizeof(dtd->part2)); - status = intel_sdvo_read_response(intel_sdvo, NULL, 0); - if (status != SDVO_CMD_STATUS_SUCCESS) - return false; - - return true; + return intel_sdvo_set_value(intel_sdvo, cmd, &dtd->part1, sizeof(dtd->part1)) && + intel_sdvo_set_value(intel_sdvo, cmd + 1, &dtd->part2, sizeof(dtd->part2)); } static bool intel_sdvo_set_input_timing(struct intel_sdvo *intel_sdvo, @@ -704,7 +676,6 @@ intel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo, uint16_t height) { struct intel_sdvo_preferred_input_timing_args args; - uint8_t status; memset(&args, 0, sizeof(args)); args.clock = clock; @@ -717,54 +688,27 @@ intel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo, intel_sdvo->sdvo_lvds_fixed_mode->vdisplay != height)) args.scaled = 1; - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING, - &args, sizeof(args)); - status = intel_sdvo_read_response(intel_sdvo, NULL, 0); - if (status != SDVO_CMD_STATUS_SUCCESS) - return false; - - return true; + return intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING, + &args, sizeof(args)); } static bool intel_sdvo_get_preferred_input_timing(struct intel_sdvo *intel_sdvo, struct intel_sdvo_dtd *dtd) { - bool status; - - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1, - NULL, 0); - - status = intel_sdvo_read_response(intel_sdvo, &dtd->part1, - sizeof(dtd->part1)); - if (status != SDVO_CMD_STATUS_SUCCESS) - return false; - - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2, - NULL, 0); - - status = intel_sdvo_read_response(intel_sdvo, &dtd->part2, - sizeof(dtd->part2)); - if (status != SDVO_CMD_STATUS_SUCCESS) - return false; - - return false; + return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1, + &dtd->part1, sizeof(dtd->part1)) && + intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2, + &dtd->part2, sizeof(dtd->part2)); } static bool intel_sdvo_set_clock_rate_mult(struct intel_sdvo *intel_sdvo, u8 val) { - u8 status; - - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1); - status = intel_sdvo_read_response(intel_sdvo, NULL, 0); - if (status != SDVO_CMD_STATUS_SUCCESS) - return false; - - return true; + return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1); } static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { uint16_t width, height; uint16_t h_blank_len, h_sync_len, v_blank_len, v_sync_len; @@ -813,7 +757,7 @@ static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd, } static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode, - struct intel_sdvo_dtd *dtd) + const struct intel_sdvo_dtd *dtd) { mode->hdisplay = dtd->part1.h_active; mode->hdisplay += ((dtd->part1.h_high >> 4) & 0x0f) << 8; @@ -848,38 +792,26 @@ static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode, static bool intel_sdvo_get_supp_encode(struct intel_sdvo *intel_sdvo, struct intel_sdvo_encode *encode) { - uint8_t status; - - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_SUPP_ENCODE, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, encode, sizeof(*encode)); - if (status != SDVO_CMD_STATUS_SUCCESS) { /* non-support means DVI */ - memset(encode, 0, sizeof(*encode)); - return false; - } + if (intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_SUPP_ENCODE, + encode, sizeof(*encode))) + return true; - return true; + /* non-support means DVI */ + memset(encode, 0, sizeof(*encode)); + return false; } static bool intel_sdvo_set_encode(struct intel_sdvo *intel_sdvo, uint8_t mode) { - uint8_t status; - - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ENCODE, &mode, 1); - status = intel_sdvo_read_response(intel_sdvo, NULL, 0); - - return (status == SDVO_CMD_STATUS_SUCCESS); + return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_ENCODE, &mode, 1); } static bool intel_sdvo_set_colorimetry(struct intel_sdvo *intel_sdvo, uint8_t mode) { - uint8_t status; - - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_COLORIMETRY, &mode, 1); - status = intel_sdvo_read_response(intel_sdvo, NULL, 0); - - return (status == SDVO_CMD_STATUS_SUCCESS); + return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_COLORIMETRY, &mode, 1); } #if 0 @@ -892,8 +824,7 @@ static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo) uint8_t buf[48]; uint8_t *pos; - intel_sdvo_write_cmd(encoder, SDVO_CMD_GET_HBUF_AV_SPLIT, NULL, 0); - intel_sdvo_read_response(encoder, &av_split, 1); + intel_sdvo_get_value(encoder, SDVO_CMD_GET_HBUF_AV_SPLIT, &av_split, 1); for (i = 0; i <= av_split; i++) { set_buf_index[0] = i; set_buf_index[1] = 0; @@ -913,7 +844,7 @@ static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo) } #endif -static void intel_sdvo_set_hdmi_buf(struct intel_sdvo *intel_sdvo, +static bool intel_sdvo_set_hdmi_buf(struct intel_sdvo *intel_sdvo, int index, uint8_t *data, int8_t size, uint8_t tx_rate) { @@ -922,15 +853,18 @@ static void intel_sdvo_set_hdmi_buf(struct intel_sdvo *intel_sdvo, set_buf_index[0] = index; set_buf_index[1] = 0; - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_INDEX, - set_buf_index, 2); + if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_INDEX, + set_buf_index, 2)) + return false; for (; size > 0; size -= 8) { - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_DATA, data, 8); + if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_DATA, data, 8)) + return false; + data += 8; } - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_TXRATE, &tx_rate, 1); + return intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_TXRATE, &tx_rate, 1); } static uint8_t intel_sdvo_calc_hbuf_csum(uint8_t *data, uint8_t size) @@ -1005,7 +939,7 @@ struct dip_infoframe { } __attribute__ ((packed)) u; } __attribute__((packed)); -static void intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo, +static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo, struct drm_display_mode * mode) { struct dip_infoframe avi_if = { @@ -1016,17 +950,15 @@ static void intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo, avi_if.checksum = intel_sdvo_calc_hbuf_csum((uint8_t *)&avi_if, 4 + avi_if.len); - intel_sdvo_set_hdmi_buf(intel_sdvo, 1, (uint8_t *)&avi_if, - 4 + avi_if.len, - SDVO_HBUF_TX_VSYNC); + return intel_sdvo_set_hdmi_buf(intel_sdvo, 1, (uint8_t *)&avi_if, + 4 + avi_if.len, + SDVO_HBUF_TX_VSYNC); } -static void intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo) +static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo) { - struct intel_sdvo_tv_format format; uint32_t format_map, i; - uint8_t status; for (i = 0; i < TV_FORMAT_NUM; i++) if (tv_format_names[i] == intel_sdvo->tv_format_name) @@ -1034,113 +966,93 @@ static void intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo) format_map = 1 << i; memset(&format, 0, sizeof(format)); - memcpy(&format, &format_map, sizeof(format_map) > sizeof(format) ? - sizeof(format) : sizeof(format_map)); - - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_TV_FORMAT, &format, - sizeof(format)); + memcpy(&format, &format_map, min(sizeof(format), sizeof(format_map))); - status = intel_sdvo_read_response(intel_sdvo, NULL, 0); - if (status != SDVO_CMD_STATUS_SUCCESS) - DRM_DEBUG_KMS("%s: Failed to set TV format\n", - SDVO_NAME(intel_sdvo)); + BUILD_BUG_ON(sizeof(format) != 6); + return intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_TV_FORMAT, + &format, sizeof(format)); } -static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +static bool +intel_sdvo_set_output_timings_from_mode(struct intel_sdvo *intel_sdvo, + struct drm_display_mode *mode) { - struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); + struct intel_sdvo_dtd output_dtd; - if (intel_sdvo->is_tv) { - struct intel_sdvo_dtd output_dtd; - bool success; + if (!intel_sdvo_set_target_output(intel_sdvo, + intel_sdvo->attached_output)) + return false; - /* We need to construct preferred input timings based on our - * output timings. To do that, we have to set the output - * timings, even though this isn't really the right place in - * the sequence to do it. Oh well. - */ + intel_sdvo_get_dtd_from_mode(&output_dtd, mode); + if (!intel_sdvo_set_output_timing(intel_sdvo, &output_dtd)) + return false; + return true; +} + +static bool +intel_sdvo_set_input_timings_for_mode(struct intel_sdvo *intel_sdvo, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct intel_sdvo_dtd input_dtd; - /* Set output timings */ - intel_sdvo_get_dtd_from_mode(&output_dtd, mode); - intel_sdvo_set_target_output(intel_sdvo, - intel_sdvo->attached_output); - intel_sdvo_set_output_timing(intel_sdvo, &output_dtd); + /* Reset the input timing to the screen. Assume always input 0. */ + if (!intel_sdvo_set_target_input(intel_sdvo)) + return false; - /* Set the input timing to the screen. Assume always input 0. */ - intel_sdvo_set_target_input(intel_sdvo, true, false); + if (!intel_sdvo_create_preferred_input_timing(intel_sdvo, + mode->clock / 10, + mode->hdisplay, + mode->vdisplay)) + return false; + if (!intel_sdvo_get_preferred_input_timing(intel_sdvo, + &input_dtd)) + return false; - success = intel_sdvo_create_preferred_input_timing(intel_sdvo, - mode->clock / 10, - mode->hdisplay, - mode->vdisplay); - if (success) { - struct intel_sdvo_dtd input_dtd; + intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd); + intel_sdvo->sdvo_flags = input_dtd.part2.sdvo_flags; - intel_sdvo_get_preferred_input_timing(intel_sdvo, - &input_dtd); - intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd); - intel_sdvo->sdvo_flags = input_dtd.part2.sdvo_flags; + drm_mode_set_crtcinfo(adjusted_mode, 0); + mode->clock = adjusted_mode->clock; + return true; +} - drm_mode_set_crtcinfo(adjusted_mode, 0); +static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); - mode->clock = adjusted_mode->clock; + /* We need to construct preferred input timings based on our + * output timings. To do that, we have to set the output + * timings, even though this isn't really the right place in + * the sequence to do it. Oh well. + */ + if (intel_sdvo->is_tv) { + if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, mode)) + return false; - adjusted_mode->clock *= - intel_sdvo_get_pixel_multiplier(mode); - } else { + if (!intel_sdvo_set_input_timings_for_mode(intel_sdvo, mode, adjusted_mode)) return false; - } } else if (intel_sdvo->is_lvds) { - struct intel_sdvo_dtd output_dtd; - bool success; - drm_mode_set_crtcinfo(intel_sdvo->sdvo_lvds_fixed_mode, 0); - /* Set output timings */ - intel_sdvo_get_dtd_from_mode(&output_dtd, - intel_sdvo->sdvo_lvds_fixed_mode); - - intel_sdvo_set_target_output(intel_sdvo, - intel_sdvo->attached_output); - intel_sdvo_set_output_timing(intel_sdvo, &output_dtd); - - /* Set the input timing to the screen. Assume always input 0. */ - intel_sdvo_set_target_input(intel_sdvo, true, false); - - - success = intel_sdvo_create_preferred_input_timing( - intel_sdvo, - mode->clock / 10, - mode->hdisplay, - mode->vdisplay); - - if (success) { - struct intel_sdvo_dtd input_dtd; - - intel_sdvo_get_preferred_input_timing(intel_sdvo, - &input_dtd); - intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd); - intel_sdvo->sdvo_flags = input_dtd.part2.sdvo_flags; - drm_mode_set_crtcinfo(adjusted_mode, 0); - - mode->clock = adjusted_mode->clock; - - adjusted_mode->clock *= - intel_sdvo_get_pixel_multiplier(mode); - } else { + if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, + intel_sdvo->sdvo_lvds_fixed_mode)) return false; - } - } else { - /* Make the CRTC code factor in the SDVO pixel multiplier. The - * SDVO device will be told of the multiplier during mode_set. - */ - adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode); + if (!intel_sdvo_set_input_timings_for_mode(intel_sdvo, mode, adjusted_mode)) + return false; } + + /* Make the CRTC code factor in the SDVO pixel multiplier. The + * SDVO device will be told of the multiplier during mode_set. + */ + adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode); + return true; } @@ -1154,10 +1066,9 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); u32 sdvox = 0; - int sdvo_pixel_multiply; + int sdvo_pixel_multiply, rate; struct intel_sdvo_in_out_map in_out; struct intel_sdvo_dtd input_dtd; - u8 status; if (!mode) return; @@ -1171,12 +1082,15 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, in_out.in0 = intel_sdvo->attached_output; in_out.in1 = 0; - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_IN_OUT_MAP, - &in_out, sizeof(in_out)); - status = intel_sdvo_read_response(intel_sdvo, NULL, 0); + if (!intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_IN_OUT_MAP, + &in_out, sizeof(in_out))) + return; if (intel_sdvo->is_hdmi) { - intel_sdvo_set_avi_infoframe(intel_sdvo, mode); + if (!intel_sdvo_set_avi_infoframe(intel_sdvo, mode)) + return; + sdvox |= SDVO_AUDIO_ENABLE; } @@ -1193,16 +1107,22 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, */ if (!intel_sdvo->is_tv && !intel_sdvo->is_lvds) { /* Set the output timing to the screen */ - intel_sdvo_set_target_output(intel_sdvo, - intel_sdvo->attached_output); - intel_sdvo_set_output_timing(intel_sdvo, &input_dtd); + if (!intel_sdvo_set_target_output(intel_sdvo, + intel_sdvo->attached_output)) + return; + + if (!intel_sdvo_set_output_timing(intel_sdvo, &input_dtd)) + return; } /* Set the input timing to the screen. Assume always input 0. */ - intel_sdvo_set_target_input(intel_sdvo, true, false); + if (!intel_sdvo_set_target_input(intel_sdvo)) + return; - if (intel_sdvo->is_tv) - intel_sdvo_set_tv_format(intel_sdvo); + if (intel_sdvo->is_tv) { + if (!intel_sdvo_set_tv_format(intel_sdvo)) + return; + } /* We would like to use intel_sdvo_create_preferred_input_timing() to * provide the device with a timing it can support, if it supports that @@ -1219,23 +1139,18 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, intel_sdvo_set_input_timing(encoder, &input_dtd); } #else - intel_sdvo_set_input_timing(intel_sdvo, &input_dtd); + if (!intel_sdvo_set_input_timing(intel_sdvo, &input_dtd)) + return; #endif - switch (intel_sdvo_get_pixel_multiplier(mode)) { - case 1: - intel_sdvo_set_clock_rate_mult(intel_sdvo, - SDVO_CLOCK_RATE_MULT_1X); - break; - case 2: - intel_sdvo_set_clock_rate_mult(intel_sdvo, - SDVO_CLOCK_RATE_MULT_2X); - break; - case 4: - intel_sdvo_set_clock_rate_mult(intel_sdvo, - SDVO_CLOCK_RATE_MULT_4X); - break; + sdvo_pixel_multiply = intel_sdvo_get_pixel_multiplier(mode); + switch (sdvo_pixel_multiply) { + case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break; + case 2: rate = SDVO_CLOCK_RATE_MULT_2X; break; + case 4: rate = SDVO_CLOCK_RATE_MULT_4X; break; } + if (!intel_sdvo_set_clock_rate_mult(intel_sdvo, rate)) + return; /* Set the SDVO control regs. */ if (IS_I965G(dev)) { @@ -1259,7 +1174,6 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, if (intel_crtc->pipe == 1) sdvox |= SDVO_PIPE_B_SELECT; - sdvo_pixel_multiply = intel_sdvo_get_pixel_multiplier(mode); if (IS_I965G(dev)) { /* done in crtc_mode_set as the dpll_md reg must be written early */ } else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) { @@ -1302,10 +1216,7 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) for (i = 0; i < 2; i++) intel_wait_for_vblank(dev); - status = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, - &input2); - - + status = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2); /* Warn if the device reported failure to sync. * A lot of SDVO devices fail to notify of sync, but it's * a given it the status is a success, we succeeded. @@ -1353,14 +1264,7 @@ static int intel_sdvo_mode_valid(struct drm_connector *connector, static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct intel_sdvo_caps *caps) { - u8 status; - - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_DEVICE_CAPS, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, caps, sizeof(*caps)); - if (status != SDVO_CMD_STATUS_SUCCESS) - return false; - - return true; + return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_DEVICE_CAPS, caps, sizeof(*caps)); } /* No use! */ @@ -1403,13 +1307,8 @@ int intel_sdvo_supports_hotplug(struct drm_connector *connector) intel_sdvo = to_intel_sdvo(connector); - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, &response, 2); - - if (response[0] !=0) - return 1; - - return 0; + return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT, + &response, 2) && response[0]; } void intel_sdvo_set_hotplug(struct drm_connector *connector, int on) @@ -1492,8 +1391,8 @@ static int intel_analog_is_connected(struct drm_device *dev) { struct drm_connector *analog_connector; - analog_connector = intel_find_analog_connector(dev); + analog_connector = intel_find_analog_connector(dev); if (!analog_connector) return false; @@ -1569,25 +1468,23 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connector) { uint16_t response; - u8 status; struct drm_encoder *encoder = intel_attached_encoder(connector); struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); enum drm_connector_status ret; - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0); + if (!intel_sdvo_write_cmd(intel_sdvo, + SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0)) + return connector_status_unknown; if (intel_sdvo->is_tv) { /* add 30ms delay when the output type is SDVO-TV */ mdelay(30); } - status = intel_sdvo_read_response(intel_sdvo, &response, 2); + if (!intel_sdvo_read_response(intel_sdvo, &response, 2)) + return connector_status_unknown; DRM_DEBUG_KMS("SDVO response %d %d\n", response & 0xff, response >> 8); - if (status != SDVO_CMD_STATUS_SUCCESS) - return connector_status_unknown; - if (response == 0) return connector_status_disconnected; @@ -1713,8 +1610,6 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) struct intel_sdvo_sdtv_resolution_request tv_res; uint32_t reply = 0, format_map = 0; int i; - uint8_t status; - /* Read the list of supported input resolutions for the selected TV * format. @@ -1725,23 +1620,23 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) format_map = (1 << i); memcpy(&tv_res, &format_map, - sizeof(struct intel_sdvo_sdtv_resolution_request) > - sizeof(format_map) ? sizeof(format_map) : - sizeof(struct intel_sdvo_sdtv_resolution_request)); + min(sizeof(format_map), sizeof(struct intel_sdvo_sdtv_resolution_request))); - intel_sdvo_set_target_output(intel_sdvo, intel_sdvo->attached_output); + if (!intel_sdvo_set_target_output(intel_sdvo, intel_sdvo->attached_output)) + return; - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT, - &tv_res, sizeof(tv_res)); - status = intel_sdvo_read_response(intel_sdvo, &reply, 3); - if (status != SDVO_CMD_STATUS_SUCCESS) + BUILD_BUG_ON(sizeof(tv_res) != 3); + if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT, + &tv_res, sizeof(tv_res))) + return; + if (!intel_sdvo_read_response(intel_sdvo, &reply, 3)) return; for (i = 0; i < ARRAY_SIZE(sdvo_tv_modes); i++) if (reply & (1 << i)) { struct drm_display_mode *nmode; nmode = drm_mode_duplicate(connector->dev, - &sdvo_tv_modes[i]); + &sdvo_tv_modes[i]); if (nmode) drm_mode_probed_add(connector, nmode); } @@ -1798,9 +1693,7 @@ static int intel_sdvo_get_modes(struct drm_connector *connector) else intel_sdvo_get_ddc_modes(connector); - if (list_empty(&connector->probed_modes)) - return 0; - return 1; + return !list_empty(&connector->probed_modes); } static @@ -1831,7 +1724,7 @@ void intel_sdvo_destroy_enhance_property(struct drm_connector *connector) if (intel_sdvo_connector->hue_property) drm_property_destroy(dev, intel_sdvo_connector->hue_property); } - if (IS_TV(intel_sdvo_connector) || IS_LVDS(intel_sdvo_connector)) { + if (IS_TV_OR_LVDS(intel_sdvo_connector)) { if (intel_sdvo_connector->brightness_property) drm_property_destroy(dev, intel_sdvo_connector->brightness_property); @@ -1862,36 +1755,33 @@ intel_sdvo_set_property(struct drm_connector *connector, struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); struct drm_crtc *crtc = encoder->crtc; - int ret = 0; bool changed = false; - uint8_t cmd, status; uint16_t temp_value; + uint8_t cmd; + int ret; ret = drm_connector_property_set_value(connector, property, val); - if (ret < 0) - goto out; + if (ret) + return ret; if (property == intel_sdvo_connector->tv_format_property) { - if (val >= TV_FORMAT_NUM) { - ret = -EINVAL; - goto out; - } + if (val >= TV_FORMAT_NUM) + return -EINVAL; + if (intel_sdvo->tv_format_name == intel_sdvo_connector->tv_format_supported[val]) - goto out; + return 0; intel_sdvo->tv_format_name = intel_sdvo_connector->tv_format_supported[val]; changed = true; - } - - if (IS_TV(intel_sdvo_connector) || IS_LVDS(intel_sdvo_connector)) { + } else if (IS_TV_OR_LVDS(intel_sdvo_connector)) { cmd = 0; temp_value = val; if (intel_sdvo_connector->left_property == property) { drm_connector_property_set_value(connector, intel_sdvo_connector->right_property, val); if (intel_sdvo_connector->left_margin == temp_value) - goto out; + return 0; intel_sdvo_connector->left_margin = temp_value; intel_sdvo_connector->right_margin = temp_value; @@ -1902,7 +1792,7 @@ intel_sdvo_set_property(struct drm_connector *connector, drm_connector_property_set_value(connector, intel_sdvo_connector->left_property, val); if (intel_sdvo_connector->right_margin == temp_value) - goto out; + return 0; intel_sdvo_connector->left_margin = temp_value; intel_sdvo_connector->right_margin = temp_value; @@ -1913,7 +1803,7 @@ intel_sdvo_set_property(struct drm_connector *connector, drm_connector_property_set_value(connector, intel_sdvo_connector->bottom_property, val); if (intel_sdvo_connector->top_margin == temp_value) - goto out; + return 0; intel_sdvo_connector->top_margin = temp_value; intel_sdvo_connector->bottom_margin = temp_value; @@ -1924,7 +1814,8 @@ intel_sdvo_set_property(struct drm_connector *connector, drm_connector_property_set_value(connector, intel_sdvo_connector->top_property, val); if (intel_sdvo_connector->bottom_margin == temp_value) - goto out; + return 0; + intel_sdvo_connector->top_margin = temp_value; intel_sdvo_connector->bottom_margin = temp_value; temp_value = intel_sdvo_connector->max_vscan - @@ -1932,57 +1823,52 @@ intel_sdvo_set_property(struct drm_connector *connector, cmd = SDVO_CMD_SET_OVERSCAN_V; } else if (intel_sdvo_connector->hpos_property == property) { if (intel_sdvo_connector->cur_hpos == temp_value) - goto out; + return 0; cmd = SDVO_CMD_SET_POSITION_H; intel_sdvo_connector->cur_hpos = temp_value; } else if (intel_sdvo_connector->vpos_property == property) { if (intel_sdvo_connector->cur_vpos == temp_value) - goto out; + return 0; cmd = SDVO_CMD_SET_POSITION_V; intel_sdvo_connector->cur_vpos = temp_value; } else if (intel_sdvo_connector->saturation_property == property) { if (intel_sdvo_connector->cur_saturation == temp_value) - goto out; + return 0; cmd = SDVO_CMD_SET_SATURATION; intel_sdvo_connector->cur_saturation = temp_value; } else if (intel_sdvo_connector->contrast_property == property) { if (intel_sdvo_connector->cur_contrast == temp_value) - goto out; + return 0; cmd = SDVO_CMD_SET_CONTRAST; intel_sdvo_connector->cur_contrast = temp_value; } else if (intel_sdvo_connector->hue_property == property) { if (intel_sdvo_connector->cur_hue == temp_value) - goto out; + return 0; cmd = SDVO_CMD_SET_HUE; intel_sdvo_connector->cur_hue = temp_value; } else if (intel_sdvo_connector->brightness_property == property) { if (intel_sdvo_connector->cur_brightness == temp_value) - goto out; + return 0; cmd = SDVO_CMD_SET_BRIGHTNESS; intel_sdvo_connector->cur_brightness = temp_value; } if (cmd) { - intel_sdvo_write_cmd(intel_sdvo, cmd, &temp_value, 2); - status = intel_sdvo_read_response(intel_sdvo, - NULL, 0); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO command \n"); + if (!intel_sdvo_set_value(intel_sdvo, cmd, &temp_value, 2)) return -EINVAL; - } + changed = true; } } if (changed && crtc) drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->fb); -out: - return ret; + return 0; } static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = { @@ -2050,18 +1936,10 @@ intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv, static bool intel_sdvo_get_digital_encoding_mode(struct intel_sdvo *intel_sdvo, int device) { - uint8_t status; - - if (device == 0) - intel_sdvo_set_target_output(intel_sdvo, SDVO_OUTPUT_TMDS0); - else - intel_sdvo_set_target_output(intel_sdvo, SDVO_OUTPUT_TMDS1); - - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_ENCODE, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, &intel_sdvo->is_hdmi, 1); - if (status != SDVO_CMD_STATUS_SUCCESS) - return false; - return true; + return intel_sdvo_set_target_output(intel_sdvo, + device == 0 ? SDVO_OUTPUT_TMDS0 : SDVO_OUTPUT_TMDS1) && + intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ENCODE, + &intel_sdvo->is_hdmi, 1); } static struct intel_sdvo * @@ -2076,7 +1954,7 @@ intel_sdvo_chan_to_intel_sdvo(struct intel_i2c_chan *chan) return intel_sdvo; } - return NULL;; + return NULL; } static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap, @@ -2141,8 +2019,8 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg) } static void -intel_sdvo_connector_create (struct drm_encoder *encoder, - struct drm_connector *connector) +intel_sdvo_connector_init(struct drm_encoder *encoder, + struct drm_connector *connector) { drm_connector_init(encoder->dev, connector, &intel_sdvo_connector_funcs, connector->connector_type); @@ -2195,7 +2073,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) | (1 << INTEL_ANALOG_CLONE_BIT)); - intel_sdvo_connector_create(encoder, connector); + intel_sdvo_connector_init(encoder, connector); return true; } @@ -2224,13 +2102,19 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type) intel_sdvo->base.needs_tv_clock = true; intel_sdvo->base.clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT; - intel_sdvo_connector_create(encoder, connector); + intel_sdvo_connector_init(encoder, connector); - intel_sdvo_tv_create_property(connector, type); + if (!intel_sdvo_tv_create_property(intel_sdvo, intel_sdvo_connector, type)) + goto err; - intel_sdvo_create_enhance_property(connector); + if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector)) + goto err; return true; + +err: + kfree(intel_sdvo_connector); + return false; } static bool @@ -2262,7 +2146,7 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device) intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) | (1 << INTEL_ANALOG_CLONE_BIT)); - intel_sdvo_connector_create(encoder, connector); + intel_sdvo_connector_init(encoder, connector); return true; } @@ -2296,9 +2180,15 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) intel_sdvo->base.clone_mask = ((1 << INTEL_ANALOG_CLONE_BIT) | (1 << INTEL_SDVO_LVDS_CLONE_BIT)); - intel_sdvo_connector_create(encoder, connector); - intel_sdvo_create_enhance_property(connector); - return true; + intel_sdvo_connector_init(encoder, connector); + if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector)) + goto err; + + return true; + +err: + kfree(intel_sdvo_connector); + return false; } static bool @@ -2358,29 +2248,26 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags) return true; } -static void intel_sdvo_tv_create_property(struct drm_connector *connector, int type) +static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *intel_sdvo_connector, + int type) { - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); - struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); + struct drm_device *dev = intel_sdvo->base.enc.dev; struct intel_sdvo_tv_format format; uint32_t format_map, i; - uint8_t status; - intel_sdvo_set_target_output(intel_sdvo, type); + if (!intel_sdvo_set_target_output(intel_sdvo, type)) + return false; - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_SUPPORTED_TV_FORMATS, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &format, sizeof(format)); - if (status != SDVO_CMD_STATUS_SUCCESS) - return; + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_SUPPORTED_TV_FORMATS, + &format, sizeof(format))) + return false; - memcpy(&format_map, &format, sizeof(format) > sizeof(format_map) ? - sizeof(format_map) : sizeof(format)); + memcpy(&format_map, &format, min(sizeof(format_map), sizeof(format))); if (format_map == 0) - return; + return false; intel_sdvo_connector->format_supported_num = 0; for (i = 0 ; i < TV_FORMAT_NUM; i++) @@ -2392,9 +2279,8 @@ static void intel_sdvo_tv_create_property(struct drm_connector *connector, int t intel_sdvo_connector->tv_format_property = - drm_property_create( - connector->dev, DRM_MODE_PROP_ENUM, - "mode", intel_sdvo_connector->format_supported_num); + drm_property_create(dev, DRM_MODE_PROP_ENUM, + "mode", intel_sdvo_connector->format_supported_num); for (i = 0; i < intel_sdvo_connector->format_supported_num; i++) drm_property_add_enum( @@ -2402,56 +2288,45 @@ static void intel_sdvo_tv_create_property(struct drm_connector *connector, int t i, intel_sdvo_connector->tv_format_supported[i]); intel_sdvo->tv_format_name = intel_sdvo_connector->tv_format_supported[0]; - drm_connector_attach_property( - connector, intel_sdvo_connector->tv_format_property, 0); + drm_connector_attach_property(&intel_sdvo_connector->base.base, + intel_sdvo_connector->tv_format_property, 0); + return true; } -static void intel_sdvo_create_enhance_property(struct drm_connector *connector) +static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *intel_sdvo_connector) { - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); - struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); + struct drm_device *dev = intel_sdvo->base.enc.dev; + struct drm_connector *connector = &intel_sdvo_connector->base.base; struct intel_sdvo_enhancements_reply sdvo_data; - struct drm_device *dev = connector->dev; - uint8_t status; uint16_t response, data_value[2]; - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS, - NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, &sdvo_data, - sizeof(sdvo_data)); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS(" incorrect response is returned\n"); - return; - } + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS, + &sdvo_data, sizeof(sdvo_data))) + return false; + response = *((uint16_t *)&sdvo_data); if (!response) { DRM_DEBUG_KMS("No enhancement is supported\n"); - return; + return true; } if (IS_TV(intel_sdvo_connector)) { /* when horizontal overscan is supported, Add the left/right * property */ if (sdvo_data.overscan_h) { - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_MAX_OVERSCAN_H, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &data_value, 4); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO max " - "h_overscan\n"); - return; - } - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_OVERSCAN_H, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &response, 2); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO h_overscan\n"); - return; - } + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_MAX_OVERSCAN_H, + &data_value, 4)) + return false; + + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_OVERSCAN_H, + &response, 2)) + return false; + intel_sdvo_connector->max_hscan = data_value[0]; intel_sdvo_connector->left_margin = data_value[0] - response; intel_sdvo_connector->right_margin = intel_sdvo_connector->left_margin; @@ -2476,23 +2351,16 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) data_value[0], data_value[1], response); } if (sdvo_data.overscan_v) { - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_MAX_OVERSCAN_V, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &data_value, 4); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO max " - "v_overscan\n"); - return; - } - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_OVERSCAN_V, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &response, 2); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO v_overscan\n"); - return; - } + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_MAX_OVERSCAN_V, + &data_value, 4)) + return false; + + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_OVERSCAN_V, + &response, 2)) + return false; + intel_sdvo_connector->max_vscan = data_value[0]; intel_sdvo_connector->top_margin = data_value[0] - response; intel_sdvo_connector->bottom_margin = intel_sdvo_connector->top_margin; @@ -2517,22 +2385,16 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) data_value[0], data_value[1], response); } if (sdvo_data.position_h) { - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_MAX_POSITION_H, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &data_value, 4); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO Max h_pos\n"); - return; - } - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_POSITION_H, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &response, 2); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO get h_postion\n"); - return; - } + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_MAX_POSITION_H, + &data_value, 4)) + return false; + + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_POSITION_H, + &response, 2)) + return false; + intel_sdvo_connector->max_hpos = data_value[0]; intel_sdvo_connector->cur_hpos = response; intel_sdvo_connector->hpos_property = @@ -2548,22 +2410,16 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) data_value[0], data_value[1], response); } if (sdvo_data.position_v) { - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_MAX_POSITION_V, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &data_value, 4); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO Max v_pos\n"); - return; - } - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_POSITION_V, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &response, 2); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO get v_postion\n"); - return; - } + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_MAX_POSITION_V, + &data_value, 4)) + return false; + + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_POSITION_V, + &response, 2)) + return false; + intel_sdvo_connector->max_vpos = data_value[0]; intel_sdvo_connector->cur_vpos = response; intel_sdvo_connector->vpos_property = @@ -2579,22 +2435,16 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) data_value[0], data_value[1], response); } if (sdvo_data.saturation) { - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_MAX_SATURATION, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &data_value, 4); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO Max sat\n"); - return; - } - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_SATURATION, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &response, 2); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO get sat\n"); - return; - } + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_MAX_SATURATION, + &data_value, 4)) + return false; + + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_SATURATION, + &response, 2)) + return false; + intel_sdvo_connector->max_saturation = data_value[0]; intel_sdvo_connector->cur_saturation = response; intel_sdvo_connector->saturation_property = @@ -2611,22 +2461,14 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) data_value[0], data_value[1], response); } if (sdvo_data.contrast) { - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_MAX_CONTRAST, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &data_value, 4); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO Max contrast\n"); - return; - } - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_CONTRAST, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &response, 2); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO get contrast\n"); - return; - } + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_MAX_CONTRAST, &data_value, 4)) + return false; + + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_CONTRAST, &response, 2)) + return false; + intel_sdvo_connector->max_contrast = data_value[0]; intel_sdvo_connector->cur_contrast = response; intel_sdvo_connector->contrast_property = @@ -2642,22 +2484,14 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) data_value[0], data_value[1], response); } if (sdvo_data.hue) { - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_MAX_HUE, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &data_value, 4); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO Max hue\n"); - return; - } - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_HUE, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &response, 2); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO get hue\n"); - return; - } + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_MAX_HUE, &data_value, 4)) + return false; + + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_HUE, &response, 2)) + return false; + intel_sdvo_connector->max_hue = data_value[0]; intel_sdvo_connector->cur_hue = response; intel_sdvo_connector->hue_property = @@ -2673,24 +2507,16 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) data_value[0], data_value[1], response); } } - if (IS_TV(intel_sdvo_connector) || IS_LVDS(intel_sdvo_connector)) { + if (IS_TV_OR_LVDS(intel_sdvo_connector)) { if (sdvo_data.brightness) { - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_MAX_BRIGHTNESS, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &data_value, 4); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO Max bright\n"); - return; - } - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_BRIGHTNESS, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &response, 2); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO get brigh\n"); - return; - } + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_MAX_BRIGHTNESS, &data_value, 4)) + return false; + + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_BRIGHTNESS, &response, 2)) + return false; + intel_sdvo_connector->max_brightness = data_value[0]; intel_sdvo_connector->cur_brightness = response; intel_sdvo_connector->brightness_property = @@ -2707,7 +2533,7 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) data_value[0], data_value[1], response); } } - return; + return true; } bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) @@ -2773,8 +2599,7 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) "SDVOC/VGA DDC BUS"); dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS; } - - if (intel_encoder->ddc_bus == NULL) + if (intel_encoder->ddc_bus == NULL || intel_sdvo->analog_ddc_bus == NULL) goto err_i2c; /* Wrap with our custom algo which switches to DDC mode */ @@ -2785,24 +2610,26 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) drm_encoder_helper_add(&intel_encoder->enc, &intel_sdvo_helper_funcs); /* In default case sdvo lvds is false */ - intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps); + if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps)) + goto err_enc; if (intel_sdvo_output_setup(intel_sdvo, intel_sdvo->caps.output_flags) != true) { DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n", IS_SDVOB(sdvo_reg) ? 'B' : 'C'); - goto err_i2c; + goto err_enc; } intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg); /* Set the input timing to the screen. Assume always input 0. */ - intel_sdvo_set_target_input(intel_sdvo, true, false); - - intel_sdvo_get_input_pixel_clock_range(intel_sdvo, - &intel_sdvo->pixel_clock_min, - &intel_sdvo->pixel_clock_max); + if (!intel_sdvo_set_target_input(intel_sdvo)) + goto err_enc; + if (!intel_sdvo_get_input_pixel_clock_range(intel_sdvo, + &intel_sdvo->pixel_clock_min, + &intel_sdvo->pixel_clock_max)) + goto err_enc; DRM_DEBUG_KMS("%s device VID/DID: %02X:%02X.%02X, " "clock range %dMHz - %dMHz, " @@ -2820,9 +2647,10 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N', intel_sdvo->caps.output_flags & (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N'); - return true; +err_enc: + drm_encoder_cleanup(&intel_encoder->enc); err_i2c: if (intel_sdvo->analog_ddc_bus != NULL) intel_i2c_destroy(intel_sdvo->analog_ddc_bus); diff --git a/drivers/gpu/drm/i915/intel_sdvo_regs.h b/drivers/gpu/drm/i915/intel_sdvo_regs.h index ba5cdf8..4988660 100644 --- a/drivers/gpu/drm/i915/intel_sdvo_regs.h +++ b/drivers/gpu/drm/i915/intel_sdvo_regs.h @@ -312,7 +312,7 @@ struct intel_sdvo_set_target_input_args { # define SDVO_CLOCK_RATE_MULT_4X (1 << 3) #define SDVO_CMD_GET_SUPPORTED_TV_FORMATS 0x27 -/** 5 bytes of bit flags for TV formats shared by all TV format functions */ +/** 6 bytes of bit flags for TV formats shared by all TV format functions */ struct intel_sdvo_tv_format { unsigned int ntsc_m:1; unsigned int ntsc_j:1; -- cgit v0.10.2 From 400397506f96466a7f57911b33b4b9c075880994 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 13:50:26 +0100 Subject: drm/i915/sdvo: Use an integer mapping for supported tv format modes Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 300f110..ce8e443 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -98,7 +98,7 @@ struct intel_sdvo { bool is_tv; /* This is for current tv format name */ - char *tv_format_name; + int tv_format_index; /** * This is set if we treat the device as HDMI, instead of DVI. @@ -141,7 +141,7 @@ struct intel_sdvo_connector { uint16_t output_flag; /* This contains all current supported TV format */ - char *tv_format_supported[TV_FORMAT_NUM]; + u8 tv_format_supported[TV_FORMAT_NUM]; int format_supported_num; struct drm_property *tv_format_property; struct drm_property *tv_format_name_property[TV_FORMAT_NUM]; @@ -958,13 +958,9 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo, static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo) { struct intel_sdvo_tv_format format; - uint32_t format_map, i; - - for (i = 0; i < TV_FORMAT_NUM; i++) - if (tv_format_names[i] == intel_sdvo->tv_format_name) - break; + uint32_t format_map; - format_map = 1 << i; + format_map = 1 << intel_sdvo->tv_format_index; memset(&format, 0, sizeof(format)); memcpy(&format, &format_map, min(sizeof(format), sizeof(format_map))); @@ -1614,11 +1610,7 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) /* Read the list of supported input resolutions for the selected TV * format. */ - for (i = 0; i < TV_FORMAT_NUM; i++) - if (tv_format_names[i] == intel_sdvo->tv_format_name) - break; - - format_map = (1 << i); + format_map = 1 << intel_sdvo->tv_format_index; memcpy(&tv_res, &format_map, min(sizeof(format_map), sizeof(struct intel_sdvo_sdtv_resolution_request))); @@ -1640,7 +1632,6 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) if (nmode) drm_mode_probed_add(connector, nmode); } - } static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) @@ -1768,11 +1759,11 @@ intel_sdvo_set_property(struct drm_connector *connector, if (val >= TV_FORMAT_NUM) return -EINVAL; - if (intel_sdvo->tv_format_name == + if (intel_sdvo->tv_format_index == intel_sdvo_connector->tv_format_supported[val]) return 0; - intel_sdvo->tv_format_name = intel_sdvo_connector->tv_format_supported[val]; + intel_sdvo->tv_format_index = intel_sdvo_connector->tv_format_supported[val]; changed = true; } else if (IS_TV_OR_LVDS(intel_sdvo_connector)) { cmd = 0; @@ -2271,11 +2262,8 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo, intel_sdvo_connector->format_supported_num = 0; for (i = 0 ; i < TV_FORMAT_NUM; i++) - if (format_map & (1 << i)) { - intel_sdvo_connector->tv_format_supported - [intel_sdvo_connector->format_supported_num++] = - tv_format_names[i]; - } + if (format_map & (1 << i)) + intel_sdvo_connector->tv_format_supported[intel_sdvo_connector->format_supported_num++] = i; intel_sdvo_connector->tv_format_property = @@ -2285,9 +2273,9 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo, for (i = 0; i < intel_sdvo_connector->format_supported_num; i++) drm_property_add_enum( intel_sdvo_connector->tv_format_property, i, - i, intel_sdvo_connector->tv_format_supported[i]); + i, tv_format_names[intel_sdvo_connector->tv_format_supported[i]]); - intel_sdvo->tv_format_name = intel_sdvo_connector->tv_format_supported[0]; + intel_sdvo->tv_format_index = intel_sdvo_connector->tv_format_supported[0]; drm_connector_attach_property(&intel_sdvo_connector->base.base, intel_sdvo_connector->tv_format_property, 0); return true; -- cgit v0.10.2 From fcc8d6721cef2158398139d66cc99b5e843126a0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 13:50:27 +0100 Subject: drm/i915/sdvo: Check for allocation failure when constructing properties Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index ce8e443..72fec05 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1687,8 +1687,8 @@ static int intel_sdvo_get_modes(struct drm_connector *connector) return !list_empty(&connector->probed_modes); } -static -void intel_sdvo_destroy_enhance_property(struct drm_connector *connector) +static void +intel_sdvo_destroy_enhance_property(struct drm_connector *connector) { struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); struct drm_device *dev = connector->dev; @@ -2104,6 +2104,7 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type) return true; err: + intel_sdvo_destroy_enhance_property(connector); kfree(intel_sdvo_connector); return false; } @@ -2178,6 +2179,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) return true; err: + intel_sdvo_destroy_enhance_property(connector); kfree(intel_sdvo_connector); return false; } @@ -2269,6 +2271,8 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo, intel_sdvo_connector->tv_format_property = drm_property_create(dev, DRM_MODE_PROP_ENUM, "mode", intel_sdvo_connector->format_supported_num); + if (!intel_sdvo_connector->tv_format_property) + return false; for (i = 0; i < intel_sdvo_connector->format_supported_num; i++) drm_property_add_enum( @@ -2321,14 +2325,21 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, intel_sdvo_connector->left_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "left_margin", 2); + if (!intel_sdvo_connector->left_property) + return false; + intel_sdvo_connector->left_property->values[0] = 0; intel_sdvo_connector->left_property->values[1] = data_value[0]; drm_connector_attach_property(connector, intel_sdvo_connector->left_property, intel_sdvo_connector->left_margin); + intel_sdvo_connector->right_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "right_margin", 2); + if (!intel_sdvo_connector->right_property) + return false; + intel_sdvo_connector->right_property->values[0] = 0; intel_sdvo_connector->right_property->values[1] = data_value[0]; drm_connector_attach_property(connector, @@ -2355,14 +2366,21 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, intel_sdvo_connector->top_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "top_margin", 2); + if (!intel_sdvo_connector->top_property) + return false; + intel_sdvo_connector->top_property->values[0] = 0; intel_sdvo_connector->top_property->values[1] = data_value[0]; drm_connector_attach_property(connector, intel_sdvo_connector->top_property, intel_sdvo_connector->top_margin); + intel_sdvo_connector->bottom_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "bottom_margin", 2); + if (!intel_sdvo_connector->bottom_property) + return false; + intel_sdvo_connector->bottom_property->values[0] = 0; intel_sdvo_connector->bottom_property->values[1] = data_value[0]; drm_connector_attach_property(connector, @@ -2388,6 +2406,9 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, intel_sdvo_connector->hpos_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "hpos", 2); + if (!intel_sdvo_connector->hpos_property) + return false; + intel_sdvo_connector->hpos_property->values[0] = 0; intel_sdvo_connector->hpos_property->values[1] = data_value[0]; drm_connector_attach_property(connector, @@ -2413,6 +2434,9 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, intel_sdvo_connector->vpos_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "vpos", 2); + if (!intel_sdvo_connector->vpos_property) + return false; + intel_sdvo_connector->vpos_property->values[0] = 0; intel_sdvo_connector->vpos_property->values[1] = data_value[0]; drm_connector_attach_property(connector, @@ -2438,6 +2462,9 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, intel_sdvo_connector->saturation_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "saturation", 2); + if (!intel_sdvo_connector->saturation_property) + return false; + intel_sdvo_connector->saturation_property->values[0] = 0; intel_sdvo_connector->saturation_property->values[1] = data_value[0]; @@ -2462,6 +2489,9 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, intel_sdvo_connector->contrast_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "contrast", 2); + if (!intel_sdvo_connector->contrast_property) + return false; + intel_sdvo_connector->contrast_property->values[0] = 0; intel_sdvo_connector->contrast_property->values[1] = data_value[0]; drm_connector_attach_property(connector, @@ -2485,6 +2515,9 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, intel_sdvo_connector->hue_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "hue", 2); + if (!intel_sdvo_connector->hue_property) + return false; + intel_sdvo_connector->hue_property->values[0] = 0; intel_sdvo_connector->hue_property->values[1] = data_value[0]; @@ -2510,6 +2543,9 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, intel_sdvo_connector->brightness_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "brightness", 2); + if (!intel_sdvo_connector->brightness_property) + return false; + intel_sdvo_connector->brightness_property->values[0] = 0; intel_sdvo_connector->brightness_property->values[1] = data_value[0]; -- cgit v0.10.2 From c55217064eb728fc9348de781979b533e7cc116c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 13:50:28 +0100 Subject: drm/i915/sdvo: Add missing TV filters Reference: Bug 28634 - missing TV parameter "Flicker Filter" https://bugs.freedesktop.org/show_bug.cgi?id=28634 Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 72fec05..2344fb0 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -143,31 +143,31 @@ struct intel_sdvo_connector { /* This contains all current supported TV format */ u8 tv_format_supported[TV_FORMAT_NUM]; int format_supported_num; - struct drm_property *tv_format_property; - struct drm_property *tv_format_name_property[TV_FORMAT_NUM]; - - /** - * Returned SDTV resolutions allowed for the current format, if the - * device reported it. - */ - struct intel_sdvo_sdtv_resolution_reply sdtv_resolutions; + struct drm_property *tv_format; /* add the property for the SDVO-TV */ - struct drm_property *left_property; - struct drm_property *right_property; - struct drm_property *top_property; - struct drm_property *bottom_property; - struct drm_property *hpos_property; - struct drm_property *vpos_property; + struct drm_property *left; + struct drm_property *right; + struct drm_property *top; + struct drm_property *bottom; + struct drm_property *hpos; + struct drm_property *vpos; + struct drm_property *contrast; + struct drm_property *saturation; + struct drm_property *hue; + struct drm_property *sharpness; + struct drm_property *flicker_filter; + struct drm_property *flicker_filter_adaptive; + struct drm_property *flicker_filter_2d; + struct drm_property *tv_chroma_filter; + struct drm_property *tv_luma_filter; /* add the property for the SDVO-TV/LVDS */ - struct drm_property *brightness_property; - struct drm_property *contrast_property; - struct drm_property *saturation_property; - struct drm_property *hue_property; + struct drm_property *brightness; /* Add variable to record current setting for the above property */ u32 left_margin, right_margin, top_margin, bottom_margin; + /* this is to get the range of margin.*/ u32 max_hscan, max_vscan; u32 max_hpos, cur_hpos; @@ -176,6 +176,12 @@ struct intel_sdvo_connector { u32 cur_contrast, max_contrast; u32 cur_saturation, max_saturation; u32 cur_hue, max_hue; + u32 cur_sharpness, max_sharpness; + u32 cur_flicker_filter, max_flicker_filter; + u32 cur_flicker_filter_adaptive, max_flicker_filter_adaptive; + u32 cur_flicker_filter_2d, max_flicker_filter_2d; + u32 cur_tv_chroma_filter, max_tv_chroma_filter; + u32 cur_tv_luma_filter, max_tv_luma_filter; }; static struct intel_sdvo *enc_to_intel_sdvo(struct drm_encoder *encoder) @@ -329,13 +335,14 @@ static const struct _sdvo_cmd_name { SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT), SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SCALED_HDTV_RESOLUTION_SUPPORT), SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS), + /* Add the op code for SDVO enhancements */ - SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_POSITION_H), - SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_POSITION_H), - SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_POSITION_H), - SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_POSITION_V), - SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_POSITION_V), - SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_POSITION_V), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_HPOS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HPOS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HPOS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_VPOS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_VPOS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_VPOS), SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_SATURATION), SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SATURATION), SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_SATURATION), @@ -354,6 +361,27 @@ static const struct _sdvo_cmd_name { SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_OVERSCAN_V), SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OVERSCAN_V), SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OVERSCAN_V), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_FLICKER_FILTER), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FLICKER_FILTER), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_FLICKER_FILTER), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_FLICKER_FILTER_ADAPTIVE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FLICKER_FILTER_ADAPTIVE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_FLICKER_FILTER_ADAPTIVE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_FLICKER_FILTER_2D), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FLICKER_FILTER_2D), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_FLICKER_FILTER_2D), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_SHARPNESS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SHARPNESS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_SHARPNESS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_DOT_CRAWL), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_DOT_CRAWL), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_TV_CHROMA_FILTER), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_CHROMA_FILTER), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_CHROMA_FILTER), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_TV_LUMA_FILTER), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_LUMA_FILTER), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_LUMA_FILTER), + /* HDMI op code */ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPP_ENCODE), SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ENCODE), @@ -1693,43 +1721,47 @@ intel_sdvo_destroy_enhance_property(struct drm_connector *connector) struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); struct drm_device *dev = connector->dev; - if (IS_TV(intel_sdvo_connector)) { - if (intel_sdvo_connector->left_property) - drm_property_destroy(dev, intel_sdvo_connector->left_property); - if (intel_sdvo_connector->right_property) - drm_property_destroy(dev, intel_sdvo_connector->right_property); - if (intel_sdvo_connector->top_property) - drm_property_destroy(dev, intel_sdvo_connector->top_property); - if (intel_sdvo_connector->bottom_property) - drm_property_destroy(dev, intel_sdvo_connector->bottom_property); - if (intel_sdvo_connector->hpos_property) - drm_property_destroy(dev, intel_sdvo_connector->hpos_property); - if (intel_sdvo_connector->vpos_property) - drm_property_destroy(dev, intel_sdvo_connector->vpos_property); - if (intel_sdvo_connector->saturation_property) - drm_property_destroy(dev, - intel_sdvo_connector->saturation_property); - if (intel_sdvo_connector->contrast_property) - drm_property_destroy(dev, - intel_sdvo_connector->contrast_property); - if (intel_sdvo_connector->hue_property) - drm_property_destroy(dev, intel_sdvo_connector->hue_property); - } - if (IS_TV_OR_LVDS(intel_sdvo_connector)) { - if (intel_sdvo_connector->brightness_property) - drm_property_destroy(dev, - intel_sdvo_connector->brightness_property); - } - return; + if (intel_sdvo_connector->left) + drm_property_destroy(dev, intel_sdvo_connector->left); + if (intel_sdvo_connector->right) + drm_property_destroy(dev, intel_sdvo_connector->right); + if (intel_sdvo_connector->top) + drm_property_destroy(dev, intel_sdvo_connector->top); + if (intel_sdvo_connector->bottom) + drm_property_destroy(dev, intel_sdvo_connector->bottom); + if (intel_sdvo_connector->hpos) + drm_property_destroy(dev, intel_sdvo_connector->hpos); + if (intel_sdvo_connector->vpos) + drm_property_destroy(dev, intel_sdvo_connector->vpos); + if (intel_sdvo_connector->saturation) + drm_property_destroy(dev, intel_sdvo_connector->saturation); + if (intel_sdvo_connector->contrast) + drm_property_destroy(dev, intel_sdvo_connector->contrast); + if (intel_sdvo_connector->hue) + drm_property_destroy(dev, intel_sdvo_connector->hue); + if (intel_sdvo_connector->sharpness) + drm_property_destroy(dev, intel_sdvo_connector->sharpness); + if (intel_sdvo_connector->flicker_filter) + drm_property_destroy(dev, intel_sdvo_connector->flicker_filter); + if (intel_sdvo_connector->flicker_filter_2d) + drm_property_destroy(dev, intel_sdvo_connector->flicker_filter_2d); + if (intel_sdvo_connector->flicker_filter_adaptive) + drm_property_destroy(dev, intel_sdvo_connector->flicker_filter_adaptive); + if (intel_sdvo_connector->tv_luma_filter) + drm_property_destroy(dev, intel_sdvo_connector->tv_luma_filter); + if (intel_sdvo_connector->tv_chroma_filter) + drm_property_destroy(dev, intel_sdvo_connector->tv_chroma_filter); + if (intel_sdvo_connector->brightness) + drm_property_destroy(dev, intel_sdvo_connector->brightness); } static void intel_sdvo_destroy(struct drm_connector *connector) { struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); - if (intel_sdvo_connector->tv_format_property) + if (intel_sdvo_connector->tv_format) drm_property_destroy(connector->dev, - intel_sdvo_connector->tv_format_property); + intel_sdvo_connector->tv_format); intel_sdvo_destroy_enhance_property(connector); drm_sysfs_connector_remove(connector); @@ -1745,8 +1777,6 @@ intel_sdvo_set_property(struct drm_connector *connector, struct drm_encoder *encoder = intel_attached_encoder(connector); struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); - struct drm_crtc *crtc = encoder->crtc; - bool changed = false; uint16_t temp_value; uint8_t cmd; int ret; @@ -1755,7 +1785,16 @@ intel_sdvo_set_property(struct drm_connector *connector, if (ret) return ret; - if (property == intel_sdvo_connector->tv_format_property) { +#define CHECK_PROPERTY(name, NAME) \ + if (intel_sdvo_connector->name == property) { \ + if (intel_sdvo_connector->cur_##name == temp_value) return 0; \ + if (intel_sdvo_connector->max_##name < temp_value) return -EINVAL; \ + cmd = SDVO_CMD_SET_##NAME; \ + intel_sdvo_connector->cur_##name = temp_value; \ + goto set_value; \ + } + + if (property == intel_sdvo_connector->tv_format) { if (val >= TV_FORMAT_NUM) return -EINVAL; @@ -1764,24 +1803,24 @@ intel_sdvo_set_property(struct drm_connector *connector, return 0; intel_sdvo->tv_format_index = intel_sdvo_connector->tv_format_supported[val]; - changed = true; + goto done; } else if (IS_TV_OR_LVDS(intel_sdvo_connector)) { - cmd = 0; temp_value = val; - if (intel_sdvo_connector->left_property == property) { + if (intel_sdvo_connector->left == property) { drm_connector_property_set_value(connector, - intel_sdvo_connector->right_property, val); + intel_sdvo_connector->right, val); if (intel_sdvo_connector->left_margin == temp_value) return 0; intel_sdvo_connector->left_margin = temp_value; intel_sdvo_connector->right_margin = temp_value; temp_value = intel_sdvo_connector->max_hscan - - intel_sdvo_connector->left_margin; + intel_sdvo_connector->left_margin; cmd = SDVO_CMD_SET_OVERSCAN_H; - } else if (intel_sdvo_connector->right_property == property) { + goto set_value; + } else if (intel_sdvo_connector->right == property) { drm_connector_property_set_value(connector, - intel_sdvo_connector->left_property, val); + intel_sdvo_connector->left, val); if (intel_sdvo_connector->right_margin == temp_value) return 0; @@ -1790,76 +1829,63 @@ intel_sdvo_set_property(struct drm_connector *connector, temp_value = intel_sdvo_connector->max_hscan - intel_sdvo_connector->left_margin; cmd = SDVO_CMD_SET_OVERSCAN_H; - } else if (intel_sdvo_connector->top_property == property) { + goto set_value; + } else if (intel_sdvo_connector->top == property) { drm_connector_property_set_value(connector, - intel_sdvo_connector->bottom_property, val); + intel_sdvo_connector->bottom, val); if (intel_sdvo_connector->top_margin == temp_value) return 0; intel_sdvo_connector->top_margin = temp_value; intel_sdvo_connector->bottom_margin = temp_value; temp_value = intel_sdvo_connector->max_vscan - - intel_sdvo_connector->top_margin; + intel_sdvo_connector->top_margin; cmd = SDVO_CMD_SET_OVERSCAN_V; - } else if (intel_sdvo_connector->bottom_property == property) { + goto set_value; + } else if (intel_sdvo_connector->bottom == property) { drm_connector_property_set_value(connector, - intel_sdvo_connector->top_property, val); + intel_sdvo_connector->top, val); if (intel_sdvo_connector->bottom_margin == temp_value) return 0; intel_sdvo_connector->top_margin = temp_value; intel_sdvo_connector->bottom_margin = temp_value; temp_value = intel_sdvo_connector->max_vscan - - intel_sdvo_connector->top_margin; + intel_sdvo_connector->top_margin; cmd = SDVO_CMD_SET_OVERSCAN_V; - } else if (intel_sdvo_connector->hpos_property == property) { - if (intel_sdvo_connector->cur_hpos == temp_value) - return 0; - - cmd = SDVO_CMD_SET_POSITION_H; - intel_sdvo_connector->cur_hpos = temp_value; - } else if (intel_sdvo_connector->vpos_property == property) { - if (intel_sdvo_connector->cur_vpos == temp_value) - return 0; - - cmd = SDVO_CMD_SET_POSITION_V; - intel_sdvo_connector->cur_vpos = temp_value; - } else if (intel_sdvo_connector->saturation_property == property) { - if (intel_sdvo_connector->cur_saturation == temp_value) - return 0; + goto set_value; + } + CHECK_PROPERTY(hpos, HPOS) + CHECK_PROPERTY(vpos, VPOS) + CHECK_PROPERTY(saturation, SATURATION) + CHECK_PROPERTY(contrast, CONTRAST) + CHECK_PROPERTY(hue, HUE) + CHECK_PROPERTY(brightness, BRIGHTNESS) + CHECK_PROPERTY(sharpness, SHARPNESS) + CHECK_PROPERTY(flicker_filter, FLICKER_FILTER) + CHECK_PROPERTY(flicker_filter_2d, FLICKER_FILTER_2D) + CHECK_PROPERTY(flicker_filter_adaptive, FLICKER_FILTER_ADAPTIVE) + CHECK_PROPERTY(tv_chroma_filter, TV_CHROMA_FILTER) + CHECK_PROPERTY(tv_luma_filter, TV_LUMA_FILTER) + } - cmd = SDVO_CMD_SET_SATURATION; - intel_sdvo_connector->cur_saturation = temp_value; - } else if (intel_sdvo_connector->contrast_property == property) { - if (intel_sdvo_connector->cur_contrast == temp_value) - return 0; + return -EINVAL; /* unknown property */ - cmd = SDVO_CMD_SET_CONTRAST; - intel_sdvo_connector->cur_contrast = temp_value; - } else if (intel_sdvo_connector->hue_property == property) { - if (intel_sdvo_connector->cur_hue == temp_value) - return 0; +set_value: + if (!intel_sdvo_set_value(intel_sdvo, cmd, &temp_value, 2)) + return -EIO; - cmd = SDVO_CMD_SET_HUE; - intel_sdvo_connector->cur_hue = temp_value; - } else if (intel_sdvo_connector->brightness_property == property) { - if (intel_sdvo_connector->cur_brightness == temp_value) - return 0; - cmd = SDVO_CMD_SET_BRIGHTNESS; - intel_sdvo_connector->cur_brightness = temp_value; - } - if (cmd) { - if (!intel_sdvo_set_value(intel_sdvo, cmd, &temp_value, 2)) - return -EINVAL; +done: + if (encoder->crtc) { + struct drm_crtc *crtc = encoder->crtc; - changed = true; - } - } - if (changed && crtc) drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, - crtc->y, crtc->fb); + crtc->y, crtc->fb); + } + return 0; +#undef CHECK_PROPERTY } static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = { @@ -2268,296 +2294,194 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo, intel_sdvo_connector->tv_format_supported[intel_sdvo_connector->format_supported_num++] = i; - intel_sdvo_connector->tv_format_property = + intel_sdvo_connector->tv_format = drm_property_create(dev, DRM_MODE_PROP_ENUM, "mode", intel_sdvo_connector->format_supported_num); - if (!intel_sdvo_connector->tv_format_property) + if (!intel_sdvo_connector->tv_format) return false; for (i = 0; i < intel_sdvo_connector->format_supported_num; i++) drm_property_add_enum( - intel_sdvo_connector->tv_format_property, i, + intel_sdvo_connector->tv_format, i, i, tv_format_names[intel_sdvo_connector->tv_format_supported[i]]); intel_sdvo->tv_format_index = intel_sdvo_connector->tv_format_supported[0]; drm_connector_attach_property(&intel_sdvo_connector->base.base, - intel_sdvo_connector->tv_format_property, 0); + intel_sdvo_connector->tv_format, 0); return true; } -static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, - struct intel_sdvo_connector *intel_sdvo_connector) +#define ENHANCEMENT(name, NAME) do { \ + if (enhancements.name) { \ + if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_MAX_##NAME, &data_value, 4) || \ + !intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_##NAME, &response, 2)) \ + return false; \ + intel_sdvo_connector->max_##name = data_value[0]; \ + intel_sdvo_connector->cur_##name = response; \ + intel_sdvo_connector->name = \ + drm_property_create(dev, DRM_MODE_PROP_RANGE, #name, 2); \ + if (!intel_sdvo_connector->name) return false; \ + intel_sdvo_connector->name->values[0] = 0; \ + intel_sdvo_connector->name->values[1] = data_value[0]; \ + drm_connector_attach_property(connector, \ + intel_sdvo_connector->name, \ + intel_sdvo_connector->cur_##name); \ + DRM_DEBUG_KMS(#name ": max %d, default %d, current %d\n", \ + data_value[0], data_value[1], response); \ + } \ +} while(0) + +static bool +intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *intel_sdvo_connector, + struct intel_sdvo_enhancements_reply enhancements) { struct drm_device *dev = intel_sdvo->base.enc.dev; struct drm_connector *connector = &intel_sdvo_connector->base.base; - struct intel_sdvo_enhancements_reply sdvo_data; uint16_t response, data_value[2]; - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS, - &sdvo_data, sizeof(sdvo_data))) - return false; - - response = *((uint16_t *)&sdvo_data); - if (!response) { - DRM_DEBUG_KMS("No enhancement is supported\n"); - return true; - } - if (IS_TV(intel_sdvo_connector)) { - /* when horizontal overscan is supported, Add the left/right - * property - */ - if (sdvo_data.overscan_h) { - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_MAX_OVERSCAN_H, - &data_value, 4)) - return false; - - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_OVERSCAN_H, - &response, 2)) - return false; - - intel_sdvo_connector->max_hscan = data_value[0]; - intel_sdvo_connector->left_margin = data_value[0] - response; - intel_sdvo_connector->right_margin = intel_sdvo_connector->left_margin; - intel_sdvo_connector->left_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE, - "left_margin", 2); - if (!intel_sdvo_connector->left_property) - return false; - - intel_sdvo_connector->left_property->values[0] = 0; - intel_sdvo_connector->left_property->values[1] = data_value[0]; - drm_connector_attach_property(connector, - intel_sdvo_connector->left_property, - intel_sdvo_connector->left_margin); - - intel_sdvo_connector->right_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE, - "right_margin", 2); - if (!intel_sdvo_connector->right_property) - return false; - - intel_sdvo_connector->right_property->values[0] = 0; - intel_sdvo_connector->right_property->values[1] = data_value[0]; - drm_connector_attach_property(connector, - intel_sdvo_connector->right_property, - intel_sdvo_connector->right_margin); - DRM_DEBUG_KMS("h_overscan: max %d, " - "default %d, current %d\n", - data_value[0], data_value[1], response); - } - if (sdvo_data.overscan_v) { - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_MAX_OVERSCAN_V, - &data_value, 4)) - return false; - - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_OVERSCAN_V, - &response, 2)) - return false; + /* when horizontal overscan is supported, Add the left/right property */ + if (enhancements.overscan_h) { + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_MAX_OVERSCAN_H, + &data_value, 4)) + return false; - intel_sdvo_connector->max_vscan = data_value[0]; - intel_sdvo_connector->top_margin = data_value[0] - response; - intel_sdvo_connector->bottom_margin = intel_sdvo_connector->top_margin; - intel_sdvo_connector->top_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE, - "top_margin", 2); - if (!intel_sdvo_connector->top_property) - return false; + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_OVERSCAN_H, + &response, 2)) + return false; - intel_sdvo_connector->top_property->values[0] = 0; - intel_sdvo_connector->top_property->values[1] = data_value[0]; - drm_connector_attach_property(connector, - intel_sdvo_connector->top_property, - intel_sdvo_connector->top_margin); + intel_sdvo_connector->max_hscan = data_value[0]; + intel_sdvo_connector->left_margin = data_value[0] - response; + intel_sdvo_connector->right_margin = intel_sdvo_connector->left_margin; + intel_sdvo_connector->left = + drm_property_create(dev, DRM_MODE_PROP_RANGE, + "left_margin", 2); + if (!intel_sdvo_connector->left) + return false; - intel_sdvo_connector->bottom_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE, - "bottom_margin", 2); - if (!intel_sdvo_connector->bottom_property) - return false; + intel_sdvo_connector->left->values[0] = 0; + intel_sdvo_connector->left->values[1] = data_value[0]; + drm_connector_attach_property(connector, + intel_sdvo_connector->left, + intel_sdvo_connector->left_margin); - intel_sdvo_connector->bottom_property->values[0] = 0; - intel_sdvo_connector->bottom_property->values[1] = data_value[0]; - drm_connector_attach_property(connector, - intel_sdvo_connector->bottom_property, - intel_sdvo_connector->bottom_margin); - DRM_DEBUG_KMS("v_overscan: max %d, " - "default %d, current %d\n", - data_value[0], data_value[1], response); - } - if (sdvo_data.position_h) { - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_MAX_POSITION_H, - &data_value, 4)) - return false; + intel_sdvo_connector->right = + drm_property_create(dev, DRM_MODE_PROP_RANGE, + "right_margin", 2); + if (!intel_sdvo_connector->right) + return false; - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_POSITION_H, - &response, 2)) - return false; + intel_sdvo_connector->right->values[0] = 0; + intel_sdvo_connector->right->values[1] = data_value[0]; + drm_connector_attach_property(connector, + intel_sdvo_connector->right, + intel_sdvo_connector->right_margin); + DRM_DEBUG_KMS("h_overscan: max %d, " + "default %d, current %d\n", + data_value[0], data_value[1], response); + } - intel_sdvo_connector->max_hpos = data_value[0]; - intel_sdvo_connector->cur_hpos = response; - intel_sdvo_connector->hpos_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE, - "hpos", 2); - if (!intel_sdvo_connector->hpos_property) - return false; + if (enhancements.overscan_v) { + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_MAX_OVERSCAN_V, + &data_value, 4)) + return false; - intel_sdvo_connector->hpos_property->values[0] = 0; - intel_sdvo_connector->hpos_property->values[1] = data_value[0]; - drm_connector_attach_property(connector, - intel_sdvo_connector->hpos_property, - intel_sdvo_connector->cur_hpos); - DRM_DEBUG_KMS("h_position: max %d, " - "default %d, current %d\n", - data_value[0], data_value[1], response); - } - if (sdvo_data.position_v) { - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_MAX_POSITION_V, - &data_value, 4)) - return false; + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_OVERSCAN_V, + &response, 2)) + return false; - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_POSITION_V, - &response, 2)) - return false; + intel_sdvo_connector->max_vscan = data_value[0]; + intel_sdvo_connector->top_margin = data_value[0] - response; + intel_sdvo_connector->bottom_margin = intel_sdvo_connector->top_margin; + intel_sdvo_connector->top = + drm_property_create(dev, DRM_MODE_PROP_RANGE, + "top_margin", 2); + if (!intel_sdvo_connector->top) + return false; - intel_sdvo_connector->max_vpos = data_value[0]; - intel_sdvo_connector->cur_vpos = response; - intel_sdvo_connector->vpos_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE, - "vpos", 2); - if (!intel_sdvo_connector->vpos_property) - return false; + intel_sdvo_connector->top->values[0] = 0; + intel_sdvo_connector->top->values[1] = data_value[0]; + drm_connector_attach_property(connector, + intel_sdvo_connector->top, + intel_sdvo_connector->top_margin); - intel_sdvo_connector->vpos_property->values[0] = 0; - intel_sdvo_connector->vpos_property->values[1] = data_value[0]; - drm_connector_attach_property(connector, - intel_sdvo_connector->vpos_property, - intel_sdvo_connector->cur_vpos); - DRM_DEBUG_KMS("v_position: max %d, " - "default %d, current %d\n", - data_value[0], data_value[1], response); - } - if (sdvo_data.saturation) { - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_MAX_SATURATION, - &data_value, 4)) - return false; + intel_sdvo_connector->bottom = + drm_property_create(dev, DRM_MODE_PROP_RANGE, + "bottom_margin", 2); + if (!intel_sdvo_connector->bottom) + return false; - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_SATURATION, - &response, 2)) - return false; + intel_sdvo_connector->bottom->values[0] = 0; + intel_sdvo_connector->bottom->values[1] = data_value[0]; + drm_connector_attach_property(connector, + intel_sdvo_connector->bottom, + intel_sdvo_connector->bottom_margin); + DRM_DEBUG_KMS("v_overscan: max %d, " + "default %d, current %d\n", + data_value[0], data_value[1], response); + } - intel_sdvo_connector->max_saturation = data_value[0]; - intel_sdvo_connector->cur_saturation = response; - intel_sdvo_connector->saturation_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE, - "saturation", 2); - if (!intel_sdvo_connector->saturation_property) - return false; + ENHANCEMENT(hpos, HPOS); + ENHANCEMENT(vpos, VPOS); + ENHANCEMENT(saturation, SATURATION); + ENHANCEMENT(contrast, CONTRAST); + ENHANCEMENT(hue, HUE); + ENHANCEMENT(sharpness, SHARPNESS); + ENHANCEMENT(brightness, BRIGHTNESS); + ENHANCEMENT(flicker_filter, FLICKER_FILTER); + ENHANCEMENT(flicker_filter_adaptive, FLICKER_FILTER_ADAPTIVE); + ENHANCEMENT(flicker_filter_2d, FLICKER_FILTER_2D); + ENHANCEMENT(tv_chroma_filter, TV_CHROMA_FILTER); + ENHANCEMENT(tv_luma_filter, TV_LUMA_FILTER); - intel_sdvo_connector->saturation_property->values[0] = 0; - intel_sdvo_connector->saturation_property->values[1] = - data_value[0]; - drm_connector_attach_property(connector, - intel_sdvo_connector->saturation_property, - intel_sdvo_connector->cur_saturation); - DRM_DEBUG_KMS("saturation: max %d, " - "default %d, current %d\n", - data_value[0], data_value[1], response); - } - if (sdvo_data.contrast) { - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_MAX_CONTRAST, &data_value, 4)) - return false; + return true; +} - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_CONTRAST, &response, 2)) - return false; +static bool +intel_sdvo_create_enhance_property_lvds(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *intel_sdvo_connector, + struct intel_sdvo_enhancements_reply enhancements) +{ + struct drm_device *dev = intel_sdvo->base.enc.dev; + struct drm_connector *connector = &intel_sdvo_connector->base.base; + uint16_t response, data_value[2]; - intel_sdvo_connector->max_contrast = data_value[0]; - intel_sdvo_connector->cur_contrast = response; - intel_sdvo_connector->contrast_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE, - "contrast", 2); - if (!intel_sdvo_connector->contrast_property) - return false; + ENHANCEMENT(brightness, BRIGHTNESS); - intel_sdvo_connector->contrast_property->values[0] = 0; - intel_sdvo_connector->contrast_property->values[1] = data_value[0]; - drm_connector_attach_property(connector, - intel_sdvo_connector->contrast_property, - intel_sdvo_connector->cur_contrast); - DRM_DEBUG_KMS("contrast: max %d, " - "default %d, current %d\n", - data_value[0], data_value[1], response); - } - if (sdvo_data.hue) { - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_MAX_HUE, &data_value, 4)) - return false; + return true; +} +#undef ENHANCEMENT - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_HUE, &response, 2)) - return false; +static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *intel_sdvo_connector) +{ + union { + struct intel_sdvo_enhancements_reply reply; + uint16_t response; + } enhancements; - intel_sdvo_connector->max_hue = data_value[0]; - intel_sdvo_connector->cur_hue = response; - intel_sdvo_connector->hue_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE, - "hue", 2); - if (!intel_sdvo_connector->hue_property) - return false; + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS, + &enhancements, sizeof(enhancements))) + return false; - intel_sdvo_connector->hue_property->values[0] = 0; - intel_sdvo_connector->hue_property->values[1] = - data_value[0]; - drm_connector_attach_property(connector, - intel_sdvo_connector->hue_property, - intel_sdvo_connector->cur_hue); - DRM_DEBUG_KMS("hue: max %d, default %d, current %d\n", - data_value[0], data_value[1], response); - } + if (enhancements.response == 0) { + DRM_DEBUG_KMS("No enhancement is supported\n"); + return true; } - if (IS_TV_OR_LVDS(intel_sdvo_connector)) { - if (sdvo_data.brightness) { - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_MAX_BRIGHTNESS, &data_value, 4)) - return false; - - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_BRIGHTNESS, &response, 2)) - return false; - intel_sdvo_connector->max_brightness = data_value[0]; - intel_sdvo_connector->cur_brightness = response; - intel_sdvo_connector->brightness_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE, - "brightness", 2); - if (!intel_sdvo_connector->brightness_property) - return false; + if (IS_TV(intel_sdvo_connector)) + return intel_sdvo_create_enhance_property_tv(intel_sdvo, intel_sdvo_connector, enhancements.reply); + else if(IS_LVDS(intel_sdvo_connector)) + return intel_sdvo_create_enhance_property_lvds(intel_sdvo, intel_sdvo_connector, enhancements.reply); + else + return true; - intel_sdvo_connector->brightness_property->values[0] = 0; - intel_sdvo_connector->brightness_property->values[1] = - data_value[0]; - drm_connector_attach_property(connector, - intel_sdvo_connector->brightness_property, - intel_sdvo_connector->cur_brightness); - DRM_DEBUG_KMS("brightness: max %d, " - "default %d, current %d\n", - data_value[0], data_value[1], response); - } - } - return true; } bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) diff --git a/drivers/gpu/drm/i915/intel_sdvo_regs.h b/drivers/gpu/drm/i915/intel_sdvo_regs.h index 4988660..a386b02 100644 --- a/drivers/gpu/drm/i915/intel_sdvo_regs.h +++ b/drivers/gpu/drm/i915/intel_sdvo_regs.h @@ -596,32 +596,32 @@ struct intel_sdvo_enhancements_reply { unsigned int overscan_h:1; unsigned int overscan_v:1; - unsigned int position_h:1; - unsigned int position_v:1; + unsigned int hpos:1; + unsigned int vpos:1; unsigned int sharpness:1; unsigned int dot_crawl:1; unsigned int dither:1; - unsigned int max_tv_chroma_filter:1; - unsigned int max_tv_luma_filter:1; + unsigned int tv_chroma_filter:1; + unsigned int tv_luma_filter:1; } __attribute__((packed)); /* Picture enhancement limits below are dependent on the current TV format, * and thus need to be queried and set after it. */ -#define SDVO_CMD_GET_MAX_FLICKER_FITER 0x4d -#define SDVO_CMD_GET_MAX_ADAPTIVE_FLICKER_FITER 0x7b -#define SDVO_CMD_GET_MAX_2D_FLICKER_FITER 0x52 +#define SDVO_CMD_GET_MAX_FLICKER_FILTER 0x4d +#define SDVO_CMD_GET_MAX_FLICKER_FILTER_ADAPTIVE 0x7b +#define SDVO_CMD_GET_MAX_FLICKER_FILTER_2D 0x52 #define SDVO_CMD_GET_MAX_SATURATION 0x55 #define SDVO_CMD_GET_MAX_HUE 0x58 #define SDVO_CMD_GET_MAX_BRIGHTNESS 0x5b #define SDVO_CMD_GET_MAX_CONTRAST 0x5e #define SDVO_CMD_GET_MAX_OVERSCAN_H 0x61 #define SDVO_CMD_GET_MAX_OVERSCAN_V 0x64 -#define SDVO_CMD_GET_MAX_POSITION_H 0x67 -#define SDVO_CMD_GET_MAX_POSITION_V 0x6a -#define SDVO_CMD_GET_MAX_SHARPNESS_V 0x6d -#define SDVO_CMD_GET_MAX_TV_CHROMA 0x74 -#define SDVO_CMD_GET_MAX_TV_LUMA 0x77 +#define SDVO_CMD_GET_MAX_HPOS 0x67 +#define SDVO_CMD_GET_MAX_VPOS 0x6a +#define SDVO_CMD_GET_MAX_SHARPNESS 0x6d +#define SDVO_CMD_GET_MAX_TV_CHROMA_FILTER 0x74 +#define SDVO_CMD_GET_MAX_TV_LUMA_FILTER 0x77 struct intel_sdvo_enhancement_limits_reply { u16 max_value; u16 default_value; @@ -638,10 +638,10 @@ struct intel_sdvo_enhancement_limits_reply { #define SDVO_CMD_GET_FLICKER_FILTER 0x4e #define SDVO_CMD_SET_FLICKER_FILTER 0x4f -#define SDVO_CMD_GET_ADAPTIVE_FLICKER_FITER 0x50 -#define SDVO_CMD_SET_ADAPTIVE_FLICKER_FITER 0x51 -#define SDVO_CMD_GET_2D_FLICKER_FITER 0x53 -#define SDVO_CMD_SET_2D_FLICKER_FITER 0x54 +#define SDVO_CMD_GET_FLICKER_FILTER_ADAPTIVE 0x50 +#define SDVO_CMD_SET_FLICKER_FILTER_ADAPTIVE 0x51 +#define SDVO_CMD_GET_FLICKER_FILTER_2D 0x53 +#define SDVO_CMD_SET_FLICKER_FILTER_2D 0x54 #define SDVO_CMD_GET_SATURATION 0x56 #define SDVO_CMD_SET_SATURATION 0x57 #define SDVO_CMD_GET_HUE 0x59 @@ -654,16 +654,16 @@ struct intel_sdvo_enhancement_limits_reply { #define SDVO_CMD_SET_OVERSCAN_H 0x63 #define SDVO_CMD_GET_OVERSCAN_V 0x65 #define SDVO_CMD_SET_OVERSCAN_V 0x66 -#define SDVO_CMD_GET_POSITION_H 0x68 -#define SDVO_CMD_SET_POSITION_H 0x69 -#define SDVO_CMD_GET_POSITION_V 0x6b -#define SDVO_CMD_SET_POSITION_V 0x6c +#define SDVO_CMD_GET_HPOS 0x68 +#define SDVO_CMD_SET_HPOS 0x69 +#define SDVO_CMD_GET_VPOS 0x6b +#define SDVO_CMD_SET_VPOS 0x6c #define SDVO_CMD_GET_SHARPNESS 0x6e #define SDVO_CMD_SET_SHARPNESS 0x6f -#define SDVO_CMD_GET_TV_CHROMA 0x75 -#define SDVO_CMD_SET_TV_CHROMA 0x76 -#define SDVO_CMD_GET_TV_LUMA 0x78 -#define SDVO_CMD_SET_TV_LUMA 0x79 +#define SDVO_CMD_GET_TV_CHROMA_FILTER 0x75 +#define SDVO_CMD_SET_TV_CHROMA_FILTER 0x76 +#define SDVO_CMD_GET_TV_LUMA_FILTER 0x78 +#define SDVO_CMD_SET_TV_LUMA_FILTER 0x79 struct intel_sdvo_enhancements_arg { u16 value; }__attribute__((packed)); -- cgit v0.10.2 From e044218a8ecb560b6fad65912a4e7e509db40414 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 13:50:29 +0100 Subject: drm/i915/sdvo: Add dot crawl property This property is slightly unusual in that it is a boolean and so has no GET_MAX command. Reference: Bug 28636 - missing TV parameter "Dot Crawl freeze" https://bugs.freedesktop.org/show_bug.cgi?id=28636 Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 2344fb0..1e31724 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -161,6 +161,7 @@ struct intel_sdvo_connector { struct drm_property *flicker_filter_2d; struct drm_property *tv_chroma_filter; struct drm_property *tv_luma_filter; + struct drm_property *dot_crawl; /* add the property for the SDVO-TV/LVDS */ struct drm_property *brightness; @@ -182,6 +183,7 @@ struct intel_sdvo_connector { u32 cur_flicker_filter_2d, max_flicker_filter_2d; u32 cur_tv_chroma_filter, max_tv_chroma_filter; u32 cur_tv_luma_filter, max_tv_luma_filter; + u32 cur_dot_crawl, max_dot_crawl; }; static struct intel_sdvo *enc_to_intel_sdvo(struct drm_encoder *encoder) @@ -1751,6 +1753,8 @@ intel_sdvo_destroy_enhance_property(struct drm_connector *connector) drm_property_destroy(dev, intel_sdvo_connector->tv_luma_filter); if (intel_sdvo_connector->tv_chroma_filter) drm_property_destroy(dev, intel_sdvo_connector->tv_chroma_filter); + if (intel_sdvo_connector->dot_crawl) + drm_property_destroy(dev, intel_sdvo_connector->dot_crawl); if (intel_sdvo_connector->brightness) drm_property_destroy(dev, intel_sdvo_connector->brightness); } @@ -1867,6 +1871,7 @@ intel_sdvo_set_property(struct drm_connector *connector, CHECK_PROPERTY(flicker_filter_adaptive, FLICKER_FILTER_ADAPTIVE) CHECK_PROPERTY(tv_chroma_filter, TV_CHROMA_FILTER) CHECK_PROPERTY(tv_luma_filter, TV_LUMA_FILTER) + CHECK_PROPERTY(dot_crawl, DOT_CRAWL) } return -EINVAL; /* unknown property */ @@ -2439,6 +2444,25 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo, ENHANCEMENT(tv_chroma_filter, TV_CHROMA_FILTER); ENHANCEMENT(tv_luma_filter, TV_LUMA_FILTER); + if (enhancements.dot_crawl) { + if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_DOT_CRAWL, &response, 2)) + return false; + + intel_sdvo_connector->max_dot_crawl = 1; + intel_sdvo_connector->cur_dot_crawl = response & 0x1; + intel_sdvo_connector->dot_crawl = + drm_property_create(dev, DRM_MODE_PROP_RANGE, "dot_crawl", 2); + if (!intel_sdvo_connector->dot_crawl) + return false; + + intel_sdvo_connector->dot_crawl->values[0] = 0; + intel_sdvo_connector->dot_crawl->values[1] = 1; + drm_connector_attach_property(connector, + intel_sdvo_connector->dot_crawl, + intel_sdvo_connector->cur_dot_crawl); + DRM_DEBUG_KMS("dot crawl: current %d\n", response); + } + return true; } -- cgit v0.10.2 From 88f356b725c8a18c4da3ee0b6dcbc647418268f2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 13:55:32 +0100 Subject: drm/i915: Only emit flushes on active rings. This avoids the excess flush and requests on idle rings (and spamming the debug log ;-) Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 906663b..e7fb379 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -285,6 +285,9 @@ typedef struct drm_i915_private { unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; int vblank_pipe; int num_pipe; + u32 flush_rings; +#define FLUSH_RENDER_RING 0x1 +#define FLUSH_BSD_RING 0x2 /* For hangcheck timer */ #define DRM_I915_HANGCHECK_PERIOD 75 /* in jiffies */ diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 2a4ed7c..fc61542 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3117,6 +3117,7 @@ static void i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; + drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); uint32_t invalidate_domains = 0; uint32_t flush_domains = 0; @@ -3179,6 +3180,13 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj) obj->pending_write_domain = obj->write_domain; obj->read_domains = obj->pending_read_domains; + if (flush_domains & I915_GEM_GPU_DOMAINS) { + if (obj_priv->ring == &dev_priv->render_ring) + dev_priv->flush_rings |= FLUSH_RENDER_RING; + else if (obj_priv->ring == &dev_priv->bsd_ring) + dev_priv->flush_rings |= FLUSH_BSD_RING; + } + dev->invalidate_domains |= invalidate_domains; dev->flush_domains |= flush_domains; #if WATCH_BUF @@ -3718,7 +3726,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, ring = &dev_priv->render_ring; } - if (args->buffer_count < 1) { DRM_ERROR("execbuf with %d buffers\n", args->buffer_count); return -EINVAL; @@ -3892,6 +3899,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, */ dev->invalidate_domains = 0; dev->flush_domains = 0; + dev_priv->flush_rings = 0; for (i = 0; i < args->buffer_count; i++) { struct drm_gem_object *obj = object_list[i]; @@ -3912,16 +3920,14 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, i915_gem_flush(dev, dev->invalidate_domains, dev->flush_domains); - if (dev->flush_domains & I915_GEM_GPU_DOMAINS) { + if (dev_priv->flush_rings & FLUSH_RENDER_RING) (void)i915_add_request(dev, file_priv, - dev->flush_domains, - &dev_priv->render_ring); - - if (HAS_BSD(dev)) - (void)i915_add_request(dev, file_priv, - dev->flush_domains, - &dev_priv->bsd_ring); - } + dev->flush_domains, + &dev_priv->render_ring); + if (dev_priv->flush_rings & FLUSH_BSD_RING) + (void)i915_add_request(dev, file_priv, + dev->flush_domains, + &dev_priv->bsd_ring); } for (i = 0; i < args->buffer_count; i++) { -- cgit v0.10.2 From 403c89ff3960c540ac4d203035078f82082411cb Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 15:25:31 +0100 Subject: drm/i915: Mark the static memory latency tables const. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9839494..f3b014f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2882,7 +2882,7 @@ struct cxsr_latency { unsigned long cursor_hpll_disable; }; -static struct cxsr_latency cxsr_latency_table[] = { +static const struct cxsr_latency cxsr_latency_table[] = { {1, 0, 800, 400, 3382, 33382, 3983, 33983}, /* DDR2-400 SC */ {1, 0, 800, 667, 3354, 33354, 3807, 33807}, /* DDR2-667 SC */ {1, 0, 800, 800, 3347, 33347, 3763, 33763}, /* DDR2-800 SC */ @@ -2920,11 +2920,13 @@ static struct cxsr_latency cxsr_latency_table[] = { {0, 1, 400, 800, 6042, 36042, 6584, 36584}, /* DDR3-800 SC */ }; -static struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, int is_ddr3, - int fsb, int mem) +static const struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, + int is_ddr3, + int fsb, + int mem) { + const struct cxsr_latency *latency; int i; - struct cxsr_latency *latency; if (fsb == 0 || mem == 0) return NULL; @@ -3035,12 +3037,12 @@ static void pineview_update_wm(struct drm_device *dev, int planea_clock, int pixel_size) { struct drm_i915_private *dev_priv = dev->dev_private; + const struct cxsr_latency *latency; u32 reg; unsigned long wm; - struct cxsr_latency *latency; int sr_clock; - latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->is_ddr3, + latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->is_ddr3, dev_priv->fsb_freq, dev_priv->mem_freq); if (!latency) { DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n"); -- cgit v0.10.2 From 0be555b66a871d711a89c301b37e763058d34d33 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 15:36:30 +0100 Subject: drm/i915: report all active objects as busy Incorporates a similar patch by Daniel Vetter, the alteration being to report the current busy state after retiring. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index fc61542..24ee462 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4365,22 +4365,34 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, } mutex_lock(&dev->struct_mutex); - /* Update the active list for the hardware's current position. - * Otherwise this only updates on a delayed timer or when irqs are - * actually unmasked, and our working set ends up being larger than - * required. - */ - i915_gem_retire_requests(dev); - obj_priv = to_intel_bo(obj); - /* Don't count being on the flushing list against the object being - * done. Otherwise, a buffer left on the flushing list but not getting - * flushed (because nobody's flushing that domain) won't ever return - * unbusy and get reused by libdrm's bo cache. The other expected - * consumer of this interface, OpenGL's occlusion queries, also specs - * that the objects get unbusy "eventually" without any interference. + /* Count all active objects as busy, even if they are currently not used + * by the gpu. Users of this interface expect objects to eventually + * become non-busy without any further actions, therefore emit any + * necessary flushes here. */ - args->busy = obj_priv->active && obj_priv->last_rendering_seqno != 0; + obj_priv = to_intel_bo(obj); + args->busy = obj_priv->active; + if (args->busy) { + /* Unconditionally flush objects, even when the gpu still uses this + * object. Userspace calling this function indicates that it wants to + * use this buffer rather sooner than later, so issuing the required + * flush earlier is beneficial. + */ + if (obj->write_domain) { + i915_gem_flush(dev, 0, obj->write_domain); + (void)i915_add_request(dev, file_priv, obj->write_domain, obj_priv->ring); + } + + /* Update the active list for the hardware's current position. + * Otherwise this only updates on a delayed timer or when irqs + * are actually unmasked, and our working set ends up being + * larger than required. + */ + i915_gem_retire_requests_ring(dev, obj_priv->ring); + + args->busy = obj_priv->active; + } drm_gem_object_unreference(obj); mutex_unlock(&dev->struct_mutex); -- cgit v0.10.2 From 69d0b96c095468526009cb3104eee561c9252a84 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 4 Aug 2010 21:22:09 +0200 Subject: drm/i915: fixup pageflip ringbuffer commands for i8xx Add a new path for 2nd gen chips that uses the commands for i81x chips (where public docs do exist) augmented with the plane bits from i915. It seems to work and doesn't result in a black screen like before. Signed-off-by: Daniel Vetter Cc: stable@kernel.org [anholt: resolved against conflict] Reviewed-by: Jesse Barnes Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f3b014f..ce7a46b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5119,12 +5119,18 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, OUT_RING(offset | obj_priv->tiling_mode); pipesrc = I915_READ(pipesrc_reg); OUT_RING(pipesrc & 0x0fff0fff); - } else { + } else if (IS_GEN3(dev)) { OUT_RING(MI_DISPLAY_FLIP_I915 | MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); OUT_RING(fb->pitch); OUT_RING(offset); OUT_RING(MI_NOOP); + } else { + OUT_RING(MI_DISPLAY_FLIP | + MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); + OUT_RING(fb->pitch); + OUT_RING(offset); + OUT_RING(MI_NOOP); } ADVANCE_LP_RING(); -- cgit v0.10.2 From 6146b3d61925116e3fecce36c2fd873665bd6614 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 4 Aug 2010 21:22:10 +0200 Subject: drm/i915: i8xx also doesn't like multiple oustanding pageflips My i855GM suffers from a 80k/s interrupt storm without this. So add 2nd gen to the list of things that don't like more than one outstanding pageflip request. Furthermore I've changed the busy loop into a ringbuffer wait. Busy-loops that don't check whether the chip died are simply evil. And performance should actually improve, because there's usually a decent amount of rendering queued on the gpu, hopefully rendering that MI_WAIT into a noop by the time it's executed. The current code holds dev->struct_mutex while executing this loop, hence stalling all other gem activity anyway. Signed-off-by: Daniel Vetter Cc: stable@kernel.org Reviewed-by: Jesse Barnes [anholt: resolved against conflict] Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ce7a46b..22966bd 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5098,14 +5098,16 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, work->pending_flip_obj = obj; if (intel_crtc->plane) - flip_mask = I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; + flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; else - flip_mask = I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT; + flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; - /* Wait for any previous flip to finish */ - if (IS_GEN3(dev)) - while (I915_READ(ISR) & flip_mask) - ; + if (IS_GEN3(dev) || IS_GEN2(dev)) { + BEGIN_LP_RING(2); + OUT_RING(MI_WAIT_FOR_EVENT | flip_mask); + OUT_RING(0); + ADVANCE_LP_RING(); + } /* Offset into the new buffer for cases of shared fbs between CRTCs */ offset = obj_priv->gtt_offset; -- cgit v0.10.2 From 87f8ebf309b2df69b57be96bf36d2d61009fd296 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 12:24:42 +0100 Subject: drm/i915: Disable the cursor for DPMS_OFF The comments have long desired that we should switch off the cursor along with the display plane, make it so. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 22966bd..24fbd0f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2470,9 +2470,6 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) /** * Sets the power management mode of the pipe and plane. - * - * This code should probably grow support for turning the cursor off and back - * on appropriately at the same time as we're turning the pipe off/on. */ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) { @@ -2487,6 +2484,9 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) intel_crtc->dpms_mode = mode; + intel_crtc->cursor_on = mode == DRM_MODE_DPMS_ON; + intel_crtc_update_cursor(crtc); + if (!dev->primary->master) return; @@ -4242,7 +4242,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc) pos = 0; - if (crtc->fb) { + if (intel_crtc->cursor_on && crtc->fb) { base = intel_crtc->cursor_addr; if (x > (int) crtc->fb->width) base = 0; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 1075d43..a44b8cb 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -154,7 +154,7 @@ struct intel_crtc { uint32_t cursor_addr; int16_t cursor_x, cursor_y; int16_t cursor_width, cursor_height; - bool cursor_visble; + bool cursor_visble, cursor_on; }; #define to_intel_crtc(x) container_of(x, struct intel_crtc, base) -- cgit v0.10.2 From ae7d49d879fd196bded306e9465e0aa5a203e971 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 12:37:41 +0100 Subject: drm/i915: Emit a backtrace if we attempt to rebind a pinned buffer This debugging trace was useful for finding the fbcon regression on i965, and it may prove useful again in future. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 24ee462..b0fb394 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4198,6 +4198,10 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) if (alignment == 0) alignment = i915_gem_get_gtt_alignment(obj); if (obj_priv->gtt_offset & (alignment - 1)) { + WARN(obj_priv->pin_count, + "bo is already pinned with incorrect alignment:" + " offset=%x, req.alignment=%x\n", + obj_priv->gtt_offset, alignment); ret = i915_gem_object_unbind(obj); if (ret) return ret; -- cgit v0.10.2 From 1741dd4aa7552055659bf74ab829a21579407f10 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 15:18:12 +0100 Subject: drm/i915: Unroll wrapping of the ringbuffer. The tail is quadword aligned, so we can add two MI_NOOP as a time. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 26362f8..df8302a 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -682,9 +682,11 @@ int intel_wrap_ring_buffer(struct drm_device *dev, } virt = (unsigned int *)(ring->virtual_start + ring->tail); - rem /= 4; - while (rem--) + rem /= 8; + while (rem--) { *virt++ = MI_NOOP; + *virt++ = MI_NOOP; + } ring->tail = 0; ring->space = ring->head - 8; -- cgit v0.10.2 From d97ed3396399126cfca1e12e2b2e2d8bbc4924e5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 15:18:13 +0100 Subject: drm/i915: Move ringbuffer accounting to begin/advance. As we check that the ringbuffer will not wrap upon emission, we do not need to check that incrementing the tail wrapped every time. However, we do upon advancing just in case the tail is now pointing at the very end of the ring. Likewise we can account for the space used during emission in begin() and avoid decrementing it for every emit. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index df8302a..7ab72af 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -731,6 +731,8 @@ void intel_ring_begin(struct drm_device *dev, intel_wrap_ring_buffer(dev, ring); if (unlikely(ring->space < n)) intel_wait_ring_buffer(dev, ring, n); + + ring->space -= n; } void intel_ring_emit(struct drm_device *dev, @@ -739,13 +741,12 @@ void intel_ring_emit(struct drm_device *dev, unsigned int *virt = ring->virtual_start + ring->tail; *virt = data; ring->tail += 4; - ring->tail &= ring->size - 1; - ring->space -= 4; } void intel_ring_advance(struct drm_device *dev, struct intel_ring_buffer *ring) { + ring->tail &= ring->size - 1; ring->advance_ring(dev, ring); } -- cgit v0.10.2 From e898cd221db65273bfc102fa20e4e228e0b8c7e1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 15:18:14 +0100 Subject: drm/i915: Inline ringbuffer_emit() As the function has been reduced to a store plus increment, the body is now smaller than the call so inline it. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 7ab72af..a5d664e 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -735,14 +735,6 @@ void intel_ring_begin(struct drm_device *dev, ring->space -= n; } -void intel_ring_emit(struct drm_device *dev, - struct intel_ring_buffer *ring, unsigned int data) -{ - unsigned int *virt = ring->virtual_start + ring->tail; - *virt = data; - ring->tail += 4; -} - void intel_ring_advance(struct drm_device *dev, struct intel_ring_buffer *ring) { diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index d5568d3..9b67eea 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -106,8 +106,16 @@ int intel_wrap_ring_buffer(struct drm_device *dev, struct intel_ring_buffer *ring); void intel_ring_begin(struct drm_device *dev, struct intel_ring_buffer *ring, int n); -void intel_ring_emit(struct drm_device *dev, - struct intel_ring_buffer *ring, u32 data); + +static inline void intel_ring_emit(struct drm_device *dev, + struct intel_ring_buffer *ring, + unsigned int data) +{ + unsigned int *virt = ring->virtual_start + ring->tail; + *virt = data; + ring->tail += 4; +} + void intel_fill_struct(struct drm_device *dev, struct intel_ring_buffer *ring, void *data, -- cgit v0.10.2 From dbd7ac9661ba321fe9c1f1b7cb5f4471a6e59570 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 15:18:15 +0100 Subject: drm/i915: Use an uncommon name for the local dev_priv in macros Using dev_priv__ avoids sparse complaining about shadowed variables in the *LP_RING() macros. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e7fb379..5cd593f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1095,26 +1095,26 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); #define I915_VERBOSE 0 #define BEGIN_LP_RING(n) do { \ - drm_i915_private_t *dev_priv = dev->dev_private; \ + drm_i915_private_t *dev_priv__ = dev->dev_private; \ if (I915_VERBOSE) \ DRM_DEBUG(" BEGIN_LP_RING %x\n", (int)(n)); \ - intel_ring_begin(dev, &dev_priv->render_ring, (n)); \ + intel_ring_begin(dev, &dev_priv__->render_ring, (n)); \ } while (0) #define OUT_RING(x) do { \ - drm_i915_private_t *dev_priv = dev->dev_private; \ + drm_i915_private_t *dev_priv__ = dev->dev_private; \ if (I915_VERBOSE) \ DRM_DEBUG(" OUT_RING %x\n", (int)(x)); \ - intel_ring_emit(dev, &dev_priv->render_ring, x); \ + intel_ring_emit(dev, &dev_priv__->render_ring, x); \ } while (0) #define ADVANCE_LP_RING() do { \ - drm_i915_private_t *dev_priv = dev->dev_private; \ + drm_i915_private_t *dev_priv__ = dev->dev_private; \ if (I915_VERBOSE) \ DRM_DEBUG("ADVANCE_LP_RING %x\n", \ - dev_priv->render_ring.tail); \ - intel_ring_advance(dev, &dev_priv->render_ring); \ + dev_priv__->render_ring.tail); \ + intel_ring_advance(dev, &dev_priv__->render_ring); \ } while(0) /** -- cgit v0.10.2 From 6ef3d4278034982c13df87c4a51e0445f762d316 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 20:26:07 +0100 Subject: drm/i915: Capture the overlay status upon a GPU hang. v2: Add the interrupt status and address. Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 9214119..92d5605 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -467,6 +467,9 @@ static int i915_error_state(struct seq_file *m, void *unused) } } + if (error->overlay) + intel_overlay_print_error_state(m, error->overlay); + out: spin_unlock_irqrestore(&dev_priv->error_lock, flags); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5cd593f..1510565 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -113,6 +113,9 @@ struct intel_opregion { int enabled; }; +struct intel_overlay; +struct intel_overlay_error_state; + struct drm_i915_master_private { drm_local_map_t *sarea; struct _drm_i915_sarea *sarea_priv; @@ -166,6 +169,7 @@ struct drm_i915_error_state { u32 purgeable:1; } *active_bo; u32 active_bo_count; + struct intel_overlay_error_state *overlay; }; struct drm_i915_display_funcs { @@ -186,8 +190,6 @@ struct drm_i915_display_funcs { /* clock gating init */ }; -struct intel_overlay; - struct intel_device_info { u8 is_mobile : 1; u8 is_i8xx : 1; @@ -1069,6 +1071,10 @@ extern bool ironlake_set_drps(struct drm_device *dev, u8 val); extern void intel_detect_pch (struct drm_device *dev); extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); +/* overlay */ +extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev); +extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error); + /** * Lock test for when it's just for synchronization of ring access. * diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 85785a8..854ab1e 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -489,6 +489,7 @@ i915_error_state_free(struct drm_device *dev, i915_error_object_free(error->batchbuffer[1]); i915_error_object_free(error->ringbuffer); kfree(error->active_bo); + kfree(error->overlay); kfree(error); } @@ -667,6 +668,8 @@ static void i915_capture_error_state(struct drm_device *dev) do_gettimeofday(&error->time); + error->overlay = intel_overlay_capture_error_state(dev); + spin_lock_irqsave(&dev_priv->error_lock, flags); if (dev_priv->first_error == NULL) { dev_priv->first_error = error; diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index d39aea2..9ae61aa 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -1416,3 +1416,99 @@ void intel_cleanup_overlay(struct drm_device *dev) kfree(dev_priv->overlay); } } + +struct intel_overlay_error_state { + struct overlay_registers regs; + unsigned long base; + u32 dovsta; + u32 isr; +}; + +struct intel_overlay_error_state * +intel_overlay_capture_error_state(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_overlay *overlay = dev_priv->overlay; + struct intel_overlay_error_state *error; + struct overlay_registers __iomem *regs; + + if (!overlay || !overlay->active) + return NULL; + + error = kmalloc(sizeof(*error), GFP_ATOMIC); + if (error == NULL) + return NULL; + + error->dovsta = I915_READ(DOVSTA); + error->isr = I915_READ(ISR); + if (OVERLAY_NONPHYSICAL(overlay->dev)) + error->base = (long) overlay->reg_bo->gtt_offset; + else + error->base = (long) overlay->reg_bo->phys_obj->handle->vaddr; + + regs = intel_overlay_map_regs_atomic(overlay); + if (!regs) + goto err; + + memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers)); + intel_overlay_unmap_regs_atomic(overlay); + + return error; + +err: + kfree(error); + return NULL; +} + +void +intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error) +{ + seq_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n", + error->dovsta, error->isr); + seq_printf(m, " Register file at 0x%08lx:\n", + error->base); + +#define P(x) seq_printf(m, " " #x ": 0x%08x\n", error->regs.x) + P(OBUF_0Y); + P(OBUF_1Y); + P(OBUF_0U); + P(OBUF_0V); + P(OBUF_1U); + P(OBUF_1V); + P(OSTRIDE); + P(YRGB_VPH); + P(UV_VPH); + P(HORZ_PH); + P(INIT_PHS); + P(DWINPOS); + P(DWINSZ); + P(SWIDTH); + P(SWIDTHSW); + P(SHEIGHT); + P(YRGBSCALE); + P(UVSCALE); + P(OCLRC0); + P(OCLRC1); + P(DCLRKV); + P(DCLRKM); + P(SCLRKVH); + P(SCLRKVL); + P(SCLRKEN); + P(OCONFIG); + P(OCMD); + P(OSTART_0Y); + P(OSTART_1Y); + P(OSTART_0U); + P(OSTART_0V); + P(OSTART_1U); + P(OSTART_1V); + P(OTILEOFF_0Y); + P(OTILEOFF_1Y); + P(OTILEOFF_0U); + P(OTILEOFF_0V); + P(OTILEOFF_1U); + P(OTILEOFF_1V); + P(FASTHSCALE); + P(UVSCALEV); +#undef P +} -- cgit v0.10.2 From bf1a10923920f56da23a118de2511a72af341d61 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:20 +0100 Subject: drm/i915: Append the object onto the inactive list on binding. In order to properly track bound objects, they need to exist on one of the inactive/active lists or be pinned. As this is a requirement, do the work inside i915_gem_bind_to_gtt() rather than dotted around the callsites. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b0fb394..75e7b89 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1137,7 +1137,6 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct drm_gem_object *obj = vma->vm_private_data; struct drm_device *dev = obj->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); pgoff_t page_offset; unsigned long pfn; @@ -1155,8 +1154,6 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) if (ret) goto unlock; - list_add_tail(&obj_priv->list, &dev_priv->mm.inactive_list); - ret = i915_gem_object_set_to_gtt_domain(obj, write); if (ret) goto unlock; @@ -1363,7 +1360,6 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_i915_gem_mmap_gtt *args = data; - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; int ret; @@ -1409,7 +1405,6 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, mutex_unlock(&dev->struct_mutex); return ret; } - list_add_tail(&obj_priv->list, &dev_priv->mm.inactive_list); } drm_gem_object_unreference(obj); @@ -2723,6 +2718,9 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) atomic_inc(&dev->gtt_count); atomic_add(obj->size, &dev->gtt_memory); + /* keep track of bounds object by adding it to the inactive list */ + list_add_tail(&obj_priv->list, &dev_priv->mm.inactive_list); + /* Assert that the object is not currently in any GPU domain. As it * wasn't in the GTT, there shouldn't be any way it could have been in * a GPU cache @@ -4223,8 +4221,7 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) atomic_inc(&dev->pin_count); atomic_add(obj->size, &dev->pin_memory); if (!obj_priv->active && - (obj->write_domain & I915_GEM_GPU_DOMAINS) == 0 && - !list_empty(&obj_priv->list)) + (obj->write_domain & I915_GEM_GPU_DOMAINS) == 0) list_del_init(&obj_priv->list); } i915_verify_inactive(dev, __FILE__, __LINE__); -- cgit v0.10.2 From 0108a3edd5c2e3b150a550d565b6aa1a67c0edbe Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 7 Aug 2010 11:01:21 +0100 Subject: drm/i915: prepare for fair lru eviction This does two little changes: - Add an alignment parameter for evict_something. It's not really great to whack a carefully sized hole into the gtt with the wrong alignment. Especially since the fallback path is a full evict. - With the inactive scan stuff we need to evict more that one object, so move the unbind call into the helper function that scans for the object to be evicted, too. And adjust its name. No functional changes in this patch, just preparation. Signed-Off-by: Daniel Vetter Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 75e7b89..f150bfd 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -35,6 +35,7 @@ #include #include +static uint32_t i915_gem_get_gtt_alignment(struct drm_gem_object *obj); static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj); static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj); static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj); @@ -48,7 +49,8 @@ static int i915_gem_object_wait_rendering(struct drm_gem_object *obj); static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment); static void i915_gem_clear_fence_reg(struct drm_gem_object *obj); -static int i915_gem_evict_something(struct drm_device *dev, int min_size); +static int i915_gem_evict_something(struct drm_device *dev, int min_size, + unsigned alignment); static int i915_gem_evict_from_inactive_list(struct drm_device *dev); static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj, struct drm_i915_gem_pwrite *args, @@ -313,7 +315,8 @@ i915_gem_object_get_pages_or_evict(struct drm_gem_object *obj) if (ret == -ENOMEM) { struct drm_device *dev = obj->dev; - ret = i915_gem_evict_something(dev, obj->size); + ret = i915_gem_evict_something(dev, obj->size, + i915_gem_get_gtt_alignment(obj)); if (ret) return ret; @@ -2005,10 +2008,12 @@ i915_gem_object_unbind(struct drm_gem_object *obj) return ret; } -static struct drm_gem_object * -i915_gem_find_inactive_object(struct drm_device *dev, int min_size) +static int +i915_gem_scan_inactive_list_and_evict(struct drm_device *dev, int min_size, + unsigned alignment, int *found) { drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; struct drm_gem_object *best = NULL; struct drm_gem_object *first = NULL; @@ -2022,14 +2027,31 @@ i915_gem_find_inactive_object(struct drm_device *dev, int min_size) (!best || obj->size < best->size)) { best = obj; if (best->size == min_size) - return best; + break; } if (!first) first = obj; } } - return best ? best : first; + obj = best ? best : first; + + if (!obj) { + *found = 0; + return 0; + } + + *found = 1; + +#if WATCH_LRU + DRM_INFO("%s: evicting %p\n", __func__, obj); +#endif + obj_priv = to_intel_bo(obj); + BUG_ON(obj_priv->pin_count != 0); + BUG_ON(obj_priv->active); + + /* Wait on the rendering and unbind the buffer. */ + return i915_gem_object_unbind(obj); } static int @@ -2115,11 +2137,11 @@ i915_gem_evict_everything(struct drm_device *dev) } static int -i915_gem_evict_something(struct drm_device *dev, int min_size) +i915_gem_evict_something(struct drm_device *dev, + int min_size, unsigned alignment) { drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_gem_object *obj; - int ret; + int ret, found; struct intel_ring_buffer *render_ring = &dev_priv->render_ring; struct intel_ring_buffer *bsd_ring = &dev_priv->bsd_ring; @@ -2129,20 +2151,11 @@ i915_gem_evict_something(struct drm_device *dev, int min_size) /* If there's an inactive buffer available now, grab it * and be done. */ - obj = i915_gem_find_inactive_object(dev, min_size); - if (obj) { - struct drm_i915_gem_object *obj_priv; - -#if WATCH_LRU - DRM_INFO("%s: evicting %p\n", __func__, obj); -#endif - obj_priv = to_intel_bo(obj); - BUG_ON(obj_priv->pin_count != 0); - BUG_ON(obj_priv->active); - - /* Wait on the rendering and unbind the buffer. */ - return i915_gem_object_unbind(obj); - } + ret = i915_gem_scan_inactive_list_and_evict(dev, min_size, + alignment, + &found); + if (found) + return ret; /* If we didn't get anything, but the ring is still processing * things, wait for the next to finish and hopefully leave us @@ -2184,6 +2197,7 @@ i915_gem_evict_something(struct drm_device *dev, int min_size) * will get moved to inactive. */ if (!list_empty(&dev_priv->mm.flushing_list)) { + struct drm_gem_object *obj = NULL; struct drm_i915_gem_object *obj_priv; /* Find an object that we can immediately reuse */ @@ -2661,7 +2675,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) #if WATCH_LRU DRM_INFO("%s: GTT full, evicting something\n", __func__); #endif - ret = i915_gem_evict_something(dev, obj->size); + ret = i915_gem_evict_something(dev, obj->size, alignment); if (ret) return ret; @@ -2679,7 +2693,8 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) if (ret == -ENOMEM) { /* first try to clear up some space from the GTT */ - ret = i915_gem_evict_something(dev, obj->size); + ret = i915_gem_evict_something(dev, obj->size, + alignment); if (ret) { /* now try to shrink everyone else */ if (gfpmask) { @@ -2709,7 +2724,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) drm_mm_put_block(obj_priv->gtt_space); obj_priv->gtt_space = NULL; - ret = i915_gem_evict_something(dev, obj->size); + ret = i915_gem_evict_something(dev, obj->size, alignment); if (ret) return ret; -- cgit v0.10.2 From 6f392d548658a17600da7faaf8a5df25ee5f01f6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:22 +0100 Subject: drm/i915: Use a common seqno for all rings. This will be used by the eviction logic to maintain fairness between the rings. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 1510565..def6ee0 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -244,6 +244,7 @@ typedef struct drm_i915_private { struct pci_dev *bridge_dev; struct intel_ring_buffer render_ring; struct intel_ring_buffer bsd_ring; + uint32_t next_seqno; drm_dma_handle_t *status_page_dmah; void *seqno_page; @@ -573,8 +574,6 @@ typedef struct drm_i915_private { */ struct delayed_work retire_work; - uint32_t next_gem_seqno; - /** * Waiting sequence number, if any */ diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index f150bfd..45b9982 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4714,6 +4714,8 @@ i915_gem_init_ringbuffer(struct drm_device *dev) goto cleanup_render_ring; } + dev_priv->next_seqno = 1; + return 0; cleanup_render_ring: diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index a5d664e..3a02425 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -33,18 +33,35 @@ #include "i915_drm.h" #include "i915_trace.h" +static u32 i915_gem_get_seqno(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + u32 seqno; + + seqno = dev_priv->next_seqno; + + /* reserve 0 for non-seqno */ + if (++dev_priv->next_seqno == 0) + dev_priv->next_seqno = 1; + + return seqno; +} + static void render_ring_flush(struct drm_device *dev, struct intel_ring_buffer *ring, u32 invalidate_domains, u32 flush_domains) { + drm_i915_private_t *dev_priv = dev->dev_private; + u32 cmd; + #if WATCH_EXEC DRM_INFO("%s: invalidate %08x flush %08x\n", __func__, invalidate_domains, flush_domains); #endif - u32 cmd; - trace_i915_gem_request_flush(dev, ring->next_seqno, + + trace_i915_gem_request_flush(dev, dev_priv->next_seqno, invalidate_domains, flush_domains); if ((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) { @@ -233,9 +250,10 @@ render_ring_add_request(struct drm_device *dev, struct drm_file *file_priv, u32 flush_domains) { - u32 seqno; drm_i915_private_t *dev_priv = dev->dev_private; - seqno = intel_ring_get_seqno(dev, ring); + u32 seqno; + + seqno = i915_gem_get_seqno(dev); if (IS_GEN6(dev)) { BEGIN_LP_RING(6); @@ -405,7 +423,9 @@ bsd_ring_add_request(struct drm_device *dev, u32 flush_domains) { u32 seqno; - seqno = intel_ring_get_seqno(dev, ring); + + seqno = i915_gem_get_seqno(dev); + intel_ring_begin(dev, ring, 4); intel_ring_emit(dev, ring, MI_STORE_DWORD_INDEX); intel_ring_emit(dev, ring, @@ -479,7 +499,7 @@ render_ring_dispatch_gem_execbuffer(struct drm_device *dev, exec_start = (uint32_t) exec_offset + exec->batch_start_offset; exec_len = (uint32_t) exec->batch_len; - trace_i915_gem_request_submit(dev, dev_priv->mm.next_gem_seqno + 1); + trace_i915_gem_request_submit(dev, dev_priv->next_seqno + 1); count = nbox ? nbox : 1; @@ -757,18 +777,6 @@ void intel_fill_struct(struct drm_device *dev, intel_ring_advance(dev, ring); } -u32 intel_ring_get_seqno(struct drm_device *dev, - struct intel_ring_buffer *ring) -{ - u32 seqno; - seqno = ring->next_seqno; - - /* reserve 0 for non-seqno */ - if (++ring->next_seqno == 0) - ring->next_seqno = 1; - return seqno; -} - struct intel_ring_buffer render_ring = { .name = "render ring", .regs = { @@ -786,7 +794,6 @@ struct intel_ring_buffer render_ring = { .head = 0, .tail = 0, .space = 0, - .next_seqno = 1, .user_irq_refcount = 0, .irq_gem_seqno = 0, .waiting_gem_seqno = 0, @@ -825,7 +832,6 @@ struct intel_ring_buffer bsd_ring = { .head = 0, .tail = 0, .space = 0, - .next_seqno = 1, .user_irq_refcount = 0, .irq_gem_seqno = 0, .waiting_gem_seqno = 0, diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 9b67eea..525e7d3 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -26,7 +26,6 @@ struct intel_ring_buffer { unsigned int head; unsigned int tail; unsigned int space; - u32 next_seqno; struct intel_hw_status_page status_page; u32 irq_gem_seqno; /* last seq seem at irq time */ -- cgit v0.10.2 From b47eb4a2b302f33adaed2a27d2b3bfc74fe35ac5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:23 +0100 Subject: drm/i915: Move the eviction logic to its own file. The eviction code is the gnarly underbelly of memory management, and is clearer if kept separated from the normal domain management in GEM. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index da78f2c..384fd45 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -8,6 +8,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \ i915_suspend.o \ i915_gem.o \ i915_gem_debug.o \ + i915_gem_evict.o \ i915_gem_tiling.o \ i915_trace_points.o \ intel_display.o \ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index def6ee0..12c8f47 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -982,6 +982,7 @@ int i915_gem_init_ringbuffer(struct drm_device *dev); void i915_gem_cleanup_ringbuffer(struct drm_device *dev); int i915_gem_do_init(struct drm_device *dev, unsigned long start, unsigned long end); +int i915_gpu_idle(struct drm_device *dev); int i915_gem_idle(struct drm_device *dev); uint32_t i915_add_request(struct drm_device *dev, struct drm_file *file_priv, @@ -1007,6 +1008,11 @@ int i915_gem_object_flush_write_domain(struct drm_gem_object *obj); void i915_gem_shrinker_init(void); void i915_gem_shrinker_exit(void); +/* i915_gem_evict.c */ +int i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignment); +int i915_gem_evict_everything(struct drm_device *dev); +int i915_gem_evict_inactive(struct drm_device *dev); + /* i915_gem_tiling.c */ void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); void i915_gem_object_do_bit_17_swizzle(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 45b9982..b5a7b00 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -49,9 +49,6 @@ static int i915_gem_object_wait_rendering(struct drm_gem_object *obj); static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment); static void i915_gem_clear_fence_reg(struct drm_gem_object *obj); -static int i915_gem_evict_something(struct drm_device *dev, int min_size, - unsigned alignment); -static int i915_gem_evict_from_inactive_list(struct drm_device *dev); static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj, struct drm_i915_gem_pwrite *args, struct drm_file *file_priv); @@ -1885,19 +1882,6 @@ i915_gem_flush(struct drm_device *dev, flush_domains); } -static void -i915_gem_flush_ring(struct drm_device *dev, - uint32_t invalidate_domains, - uint32_t flush_domains, - struct intel_ring_buffer *ring) -{ - if (flush_domains & I915_GEM_DOMAIN_CPU) - drm_agp_chipset_flush(dev); - ring->flush(dev, ring, - invalidate_domains, - flush_domains); -} - /** * Ensures that all rendering to the object has completed and the object is * safe to unbind from the GTT or access from the CPU. @@ -2008,53 +1992,7 @@ i915_gem_object_unbind(struct drm_gem_object *obj) return ret; } -static int -i915_gem_scan_inactive_list_and_evict(struct drm_device *dev, int min_size, - unsigned alignment, int *found) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; - struct drm_gem_object *best = NULL; - struct drm_gem_object *first = NULL; - - /* Try to find the smallest clean object */ - list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) { - struct drm_gem_object *obj = &obj_priv->base; - if (obj->size >= min_size) { - if ((!obj_priv->dirty || - i915_gem_object_is_purgeable(obj_priv)) && - (!best || obj->size < best->size)) { - best = obj; - if (best->size == min_size) - break; - } - if (!first) - first = obj; - } - } - - obj = best ? best : first; - - if (!obj) { - *found = 0; - return 0; - } - - *found = 1; - -#if WATCH_LRU - DRM_INFO("%s: evicting %p\n", __func__, obj); -#endif - obj_priv = to_intel_bo(obj); - BUG_ON(obj_priv->pin_count != 0); - BUG_ON(obj_priv->active); - - /* Wait on the rendering and unbind the buffer. */ - return i915_gem_object_unbind(obj); -} - -static int +int i915_gpu_idle(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -2095,147 +2033,6 @@ i915_gpu_idle(struct drm_device *dev) return ret; } -static int -i915_gem_evict_everything(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - int ret; - bool lists_empty; - - spin_lock(&dev_priv->mm.active_list_lock); - lists_empty = (list_empty(&dev_priv->mm.inactive_list) && - list_empty(&dev_priv->mm.flushing_list) && - list_empty(&dev_priv->render_ring.active_list) && - (!HAS_BSD(dev) - || list_empty(&dev_priv->bsd_ring.active_list))); - spin_unlock(&dev_priv->mm.active_list_lock); - - if (lists_empty) - return -ENOSPC; - - /* Flush everything (on to the inactive lists) and evict */ - ret = i915_gpu_idle(dev); - if (ret) - return ret; - - BUG_ON(!list_empty(&dev_priv->mm.flushing_list)); - - ret = i915_gem_evict_from_inactive_list(dev); - if (ret) - return ret; - - spin_lock(&dev_priv->mm.active_list_lock); - lists_empty = (list_empty(&dev_priv->mm.inactive_list) && - list_empty(&dev_priv->mm.flushing_list) && - list_empty(&dev_priv->render_ring.active_list) && - (!HAS_BSD(dev) - || list_empty(&dev_priv->bsd_ring.active_list))); - spin_unlock(&dev_priv->mm.active_list_lock); - BUG_ON(!lists_empty); - - return 0; -} - -static int -i915_gem_evict_something(struct drm_device *dev, - int min_size, unsigned alignment) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - int ret, found; - - struct intel_ring_buffer *render_ring = &dev_priv->render_ring; - struct intel_ring_buffer *bsd_ring = &dev_priv->bsd_ring; - for (;;) { - i915_gem_retire_requests(dev); - - /* If there's an inactive buffer available now, grab it - * and be done. - */ - ret = i915_gem_scan_inactive_list_and_evict(dev, min_size, - alignment, - &found); - if (found) - return ret; - - /* If we didn't get anything, but the ring is still processing - * things, wait for the next to finish and hopefully leave us - * a buffer to evict. - */ - if (!list_empty(&render_ring->request_list)) { - struct drm_i915_gem_request *request; - - request = list_first_entry(&render_ring->request_list, - struct drm_i915_gem_request, - list); - - ret = i915_wait_request(dev, - request->seqno, request->ring); - if (ret) - return ret; - - continue; - } - - if (HAS_BSD(dev) && !list_empty(&bsd_ring->request_list)) { - struct drm_i915_gem_request *request; - - request = list_first_entry(&bsd_ring->request_list, - struct drm_i915_gem_request, - list); - - ret = i915_wait_request(dev, - request->seqno, request->ring); - if (ret) - return ret; - - continue; - } - - /* If we didn't have anything on the request list but there - * are buffers awaiting a flush, emit one and try again. - * When we wait on it, those buffers waiting for that flush - * will get moved to inactive. - */ - if (!list_empty(&dev_priv->mm.flushing_list)) { - struct drm_gem_object *obj = NULL; - struct drm_i915_gem_object *obj_priv; - - /* Find an object that we can immediately reuse */ - list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, list) { - obj = &obj_priv->base; - if (obj->size >= min_size) - break; - - obj = NULL; - } - - if (obj != NULL) { - uint32_t seqno; - - i915_gem_flush_ring(dev, - obj->write_domain, - obj->write_domain, - obj_priv->ring); - seqno = i915_add_request(dev, NULL, - obj->write_domain, - obj_priv->ring); - if (seqno == 0) - return -ENOMEM; - continue; - } - } - - /* If we didn't do any of the above, there's no single buffer - * large enough to swap out for the new one, so just evict - * everything and start again. (This should be rare.) - */ - if (!list_empty (&dev_priv->mm.inactive_list)) - return i915_gem_evict_from_inactive_list(dev); - else - return i915_gem_evict_everything(dev); - } -} - int i915_gem_object_get_pages(struct drm_gem_object *obj, gfp_t gfpmask) @@ -4548,30 +4345,6 @@ void i915_gem_free_object(struct drm_gem_object *obj) i915_gem_free_object_tail(obj); } -/** Unbinds all inactive objects. */ -static int -i915_gem_evict_from_inactive_list(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - - while (!list_empty(&dev_priv->mm.inactive_list)) { - struct drm_gem_object *obj; - int ret; - - obj = &list_first_entry(&dev_priv->mm.inactive_list, - struct drm_i915_gem_object, - list)->base; - - ret = i915_gem_object_unbind(obj); - if (ret != 0) { - DRM_ERROR("Error unbinding object: %d\n", ret); - return ret; - } - } - - return 0; -} - int i915_gem_idle(struct drm_device *dev) { @@ -4596,7 +4369,7 @@ i915_gem_idle(struct drm_device *dev) /* Under UMS, be paranoid and evict. */ if (!drm_core_check_feature(dev, DRIVER_MODESET)) { - ret = i915_gem_evict_from_inactive_list(dev); + ret = i915_gem_evict_inactive(dev); if (ret) { mutex_unlock(&dev->struct_mutex); return ret; diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c new file mode 100644 index 0000000..479e450 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -0,0 +1,260 @@ +/* + * Copyright © 2008-2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * Chris Wilson + * + */ + +#include "drmP.h" +#include "drm.h" +#include "i915_drv.h" +#include "i915_drm.h" + +static inline int +i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj_priv) +{ + return obj_priv->madv == I915_MADV_DONTNEED; +} + +static int +i915_gem_scan_inactive_list_and_evict(struct drm_device *dev, int min_size, + unsigned alignment, int *found) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_gem_object *obj; + struct drm_i915_gem_object *obj_priv; + struct drm_gem_object *best = NULL; + struct drm_gem_object *first = NULL; + + /* Try to find the smallest clean object */ + list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) { + struct drm_gem_object *obj = &obj_priv->base; + if (obj->size >= min_size) { + if ((!obj_priv->dirty || + i915_gem_object_is_purgeable(obj_priv)) && + (!best || obj->size < best->size)) { + best = obj; + if (best->size == min_size) + break; + } + if (!first) + first = obj; + } + } + + obj = best ? best : first; + + if (!obj) { + *found = 0; + return 0; + } + + *found = 1; + +#if WATCH_LRU + DRM_INFO("%s: evicting %p\n", __func__, obj); +#endif + obj_priv = to_intel_bo(obj); + BUG_ON(obj_priv->pin_count != 0); + BUG_ON(obj_priv->active); + + /* Wait on the rendering and unbind the buffer. */ + return i915_gem_object_unbind(obj); +} + +static void +i915_gem_flush_ring(struct drm_device *dev, + uint32_t invalidate_domains, + uint32_t flush_domains, + struct intel_ring_buffer *ring) +{ + if (flush_domains & I915_GEM_DOMAIN_CPU) + drm_agp_chipset_flush(dev); + ring->flush(dev, ring, + invalidate_domains, + flush_domains); +} + +int +i915_gem_evict_something(struct drm_device *dev, + int min_size, unsigned alignment) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int ret, found; + + struct intel_ring_buffer *render_ring = &dev_priv->render_ring; + struct intel_ring_buffer *bsd_ring = &dev_priv->bsd_ring; + for (;;) { + i915_gem_retire_requests(dev); + + /* If there's an inactive buffer available now, grab it + * and be done. + */ + ret = i915_gem_scan_inactive_list_and_evict(dev, min_size, + alignment, + &found); + if (found) + return ret; + + /* If we didn't get anything, but the ring is still processing + * things, wait for the next to finish and hopefully leave us + * a buffer to evict. + */ + if (!list_empty(&render_ring->request_list)) { + struct drm_i915_gem_request *request; + + request = list_first_entry(&render_ring->request_list, + struct drm_i915_gem_request, + list); + + ret = i915_do_wait_request(dev, request->seqno, true, request->ring); + if (ret) + return ret; + + continue; + } + + if (HAS_BSD(dev) && !list_empty(&bsd_ring->request_list)) { + struct drm_i915_gem_request *request; + + request = list_first_entry(&bsd_ring->request_list, + struct drm_i915_gem_request, + list); + + ret = i915_do_wait_request(dev, request->seqno, true, request->ring); + if (ret) + return ret; + + continue; + } + + /* If we didn't have anything on the request list but there + * are buffers awaiting a flush, emit one and try again. + * When we wait on it, those buffers waiting for that flush + * will get moved to inactive. + */ + if (!list_empty(&dev_priv->mm.flushing_list)) { + struct drm_gem_object *obj = NULL; + struct drm_i915_gem_object *obj_priv; + + /* Find an object that we can immediately reuse */ + list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, list) { + obj = &obj_priv->base; + if (obj->size >= min_size) + break; + + obj = NULL; + } + + if (obj != NULL) { + uint32_t seqno; + + i915_gem_flush_ring(dev, + obj->write_domain, + obj->write_domain, + obj_priv->ring); + seqno = i915_add_request(dev, NULL, + obj->write_domain, + obj_priv->ring); + if (seqno == 0) + return -ENOMEM; + continue; + } + } + + /* If we didn't do any of the above, there's no single buffer + * large enough to swap out for the new one, so just evict + * everything and start again. (This should be rare.) + */ + if (!list_empty(&dev_priv->mm.inactive_list)) + return i915_gem_evict_inactive(dev); + else + return i915_gem_evict_everything(dev); + } +} + +int +i915_gem_evict_everything(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int ret; + bool lists_empty; + + spin_lock(&dev_priv->mm.active_list_lock); + lists_empty = (list_empty(&dev_priv->mm.inactive_list) && + list_empty(&dev_priv->mm.flushing_list) && + list_empty(&dev_priv->render_ring.active_list) && + (!HAS_BSD(dev) + || list_empty(&dev_priv->bsd_ring.active_list))); + spin_unlock(&dev_priv->mm.active_list_lock); + + if (lists_empty) + return -ENOSPC; + + /* Flush everything (on to the inactive lists) and evict */ + ret = i915_gpu_idle(dev); + if (ret) + return ret; + + BUG_ON(!list_empty(&dev_priv->mm.flushing_list)); + + ret = i915_gem_evict_inactive(dev); + if (ret) + return ret; + + spin_lock(&dev_priv->mm.active_list_lock); + lists_empty = (list_empty(&dev_priv->mm.inactive_list) && + list_empty(&dev_priv->mm.flushing_list) && + list_empty(&dev_priv->render_ring.active_list) && + (!HAS_BSD(dev) + || list_empty(&dev_priv->bsd_ring.active_list))); + spin_unlock(&dev_priv->mm.active_list_lock); + BUG_ON(!lists_empty); + + return 0; +} + +/** Unbinds all inactive objects. */ +int +i915_gem_evict_inactive(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + while (!list_empty(&dev_priv->mm.inactive_list)) { + struct drm_gem_object *obj; + int ret; + + obj = &list_first_entry(&dev_priv->mm.inactive_list, + struct drm_i915_gem_object, + list)->base; + + ret = i915_gem_object_unbind(obj); + if (ret != 0) { + DRM_ERROR("Error unbinding object: %d\n", ret); + return ret; + } + } + + return 0; +} -- cgit v0.10.2 From cd377ea93f34cbd6ec49c868b66a5a7ab184775c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:24 +0100 Subject: drm/i915: Implement fair lru eviction across both rings. (v2) Based in a large part upon Daniel Vetter's implementation and adapted for handling multiple rings in a single pass. This should lead to better gtt usage and fixes the page-fault-of-doom triggered. The fairness is provided by scanning through the GTT space amalgamating space in rendering order. As soon as we have a contiguous space in the GTT large enough for the new object (and its alignment), evict any object which lies within that space. This should keep more objects resident in the GTT. Doing throughput testing on a PineView machine with cairo-perf-trace indicates that there is very little difference with the new LRU scan, perhaps a small improvement... Except oddly for the poppler trace. Reference: Bug 15911 - Intermittent X crash (freeze) https://bugzilla.kernel.org/show_bug.cgi?id=15911 Bug 20152 - cannot view JPG in firefox when running UXA https://bugs.freedesktop.org/show_bug.cgi?id=20152 Bug 24369 - Hang when scrolling firefox page with window in front https://bugs.freedesktop.org/show_bug.cgi?id=24369 Bug 28478 - Intermittent graphics lockups due to overflow/loop https://bugs.freedesktop.org/show_bug.cgi?id=28478 v2: Attempt to clarify the logic and order of eviction through the use of comments and macros. Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 12c8f47..6221f23 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -673,6 +673,8 @@ struct drm_i915_gem_object { struct list_head list; /** This object's place on GPU write list */ struct list_head gpu_write_list; + /** This object's place on eviction list */ + struct list_head evict_list; /** * This is set if the object is on the active or flushing lists diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index 479e450..72cae3c 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -31,167 +31,178 @@ #include "i915_drv.h" #include "i915_drm.h" -static inline int -i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj_priv) -{ - return obj_priv->madv == I915_MADV_DONTNEED; -} - -static int -i915_gem_scan_inactive_list_and_evict(struct drm_device *dev, int min_size, - unsigned alignment, int *found) +static struct drm_i915_gem_object * +i915_gem_next_active_object(struct drm_device *dev, + struct list_head **render_iter, + struct list_head **bsd_iter) { drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; - struct drm_gem_object *best = NULL; - struct drm_gem_object *first = NULL; - - /* Try to find the smallest clean object */ - list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) { - struct drm_gem_object *obj = &obj_priv->base; - if (obj->size >= min_size) { - if ((!obj_priv->dirty || - i915_gem_object_is_purgeable(obj_priv)) && - (!best || obj->size < best->size)) { - best = obj; - if (best->size == min_size) - break; - } - if (!first) - first = obj; - } - } + struct drm_i915_gem_object *render_obj = NULL, *bsd_obj = NULL; - obj = best ? best : first; + if (*render_iter != &dev_priv->render_ring.active_list) + render_obj = list_entry(*render_iter, + struct drm_i915_gem_object, + list); - if (!obj) { - *found = 0; - return 0; - } + if (HAS_BSD(dev)) { + if (*bsd_iter != &dev_priv->bsd_ring.active_list) + bsd_obj = list_entry(*bsd_iter, + struct drm_i915_gem_object, + list); - *found = 1; + if (render_obj == NULL) { + *bsd_iter = (*bsd_iter)->next; + return bsd_obj; + } -#if WATCH_LRU - DRM_INFO("%s: evicting %p\n", __func__, obj); -#endif - obj_priv = to_intel_bo(obj); - BUG_ON(obj_priv->pin_count != 0); - BUG_ON(obj_priv->active); + if (bsd_obj == NULL) { + *render_iter = (*render_iter)->next; + return render_obj; + } - /* Wait on the rendering and unbind the buffer. */ - return i915_gem_object_unbind(obj); + /* XXX can we handle seqno wrapping? */ + if (render_obj->last_rendering_seqno < bsd_obj->last_rendering_seqno) { + *render_iter = (*render_iter)->next; + return render_obj; + } else { + *bsd_iter = (*bsd_iter)->next; + return bsd_obj; + } + } else { + *render_iter = (*render_iter)->next; + return render_obj; + } } -static void -i915_gem_flush_ring(struct drm_device *dev, - uint32_t invalidate_domains, - uint32_t flush_domains, - struct intel_ring_buffer *ring) +static bool +mark_free(struct drm_i915_gem_object *obj_priv, + struct list_head *unwind) { - if (flush_domains & I915_GEM_DOMAIN_CPU) - drm_agp_chipset_flush(dev); - ring->flush(dev, ring, - invalidate_domains, - flush_domains); + list_add(&obj_priv->evict_list, unwind); + return drm_mm_scan_add_block(obj_priv->gtt_space); } +#define i915_for_each_active_object(OBJ, R, B) \ + *(R) = dev_priv->render_ring.active_list.next; \ + *(B) = dev_priv->bsd_ring.active_list.next; \ + while (((OBJ) = i915_gem_next_active_object(dev, (R), (B))) != NULL) + int -i915_gem_evict_something(struct drm_device *dev, - int min_size, unsigned alignment) +i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignment) { drm_i915_private_t *dev_priv = dev->dev_private; - int ret, found; - - struct intel_ring_buffer *render_ring = &dev_priv->render_ring; - struct intel_ring_buffer *bsd_ring = &dev_priv->bsd_ring; - for (;;) { - i915_gem_retire_requests(dev); - - /* If there's an inactive buffer available now, grab it - * and be done. - */ - ret = i915_gem_scan_inactive_list_and_evict(dev, min_size, - alignment, - &found); - if (found) - return ret; + struct list_head eviction_list, unwind_list; + struct drm_i915_gem_object *obj_priv, *tmp_obj_priv; + struct list_head *render_iter, *bsd_iter; + int ret = 0; - /* If we didn't get anything, but the ring is still processing - * things, wait for the next to finish and hopefully leave us - * a buffer to evict. - */ - if (!list_empty(&render_ring->request_list)) { - struct drm_i915_gem_request *request; + i915_gem_retire_requests(dev); - request = list_first_entry(&render_ring->request_list, - struct drm_i915_gem_request, - list); + /* Re-check for free space after retiring requests */ + if (drm_mm_search_free(&dev_priv->mm.gtt_space, + min_size, alignment, 0)) + return 0; - ret = i915_do_wait_request(dev, request->seqno, true, request->ring); - if (ret) - return ret; + /* + * The goal is to evict objects and amalgamate space in LRU order. + * The oldest idle objects reside on the inactive list, which is in + * retirement order. The next objects to retire are those on the (per + * ring) active list that do not have an outstanding flush. Once the + * hardware reports completion (the seqno is updated after the + * batchbuffer has been finished) the clean buffer objects would + * be retired to the inactive list. Any dirty objects would be added + * to the tail of the flushing list. So after processing the clean + * active objects we need to emit a MI_FLUSH to retire the flushing + * list, hence the retirement order of the flushing list is in + * advance of the dirty objects on the active lists. + * + * The retirement sequence is thus: + * 1. Inactive objects (already retired) + * 2. Clean active objects + * 3. Flushing list + * 4. Dirty active objects. + * + * On each list, the oldest objects lie at the HEAD with the freshest + * object on the TAIL. + */ + + INIT_LIST_HEAD(&unwind_list); + drm_mm_init_scan(&dev_priv->mm.gtt_space, min_size, alignment); + + /* First see if there is a large enough contiguous idle region... */ + list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) { + if (mark_free(obj_priv, &unwind_list)) + goto found; + } + /* Now merge in the soon-to-be-expired objects... */ + i915_for_each_active_object(obj_priv, &render_iter, &bsd_iter) { + /* Does the object require an outstanding flush? */ + if (obj_priv->base.write_domain || obj_priv->pin_count) continue; - } - if (HAS_BSD(dev) && !list_empty(&bsd_ring->request_list)) { - struct drm_i915_gem_request *request; - - request = list_first_entry(&bsd_ring->request_list, - struct drm_i915_gem_request, - list); + if (mark_free(obj_priv, &unwind_list)) + goto found; + } - ret = i915_do_wait_request(dev, request->seqno, true, request->ring); - if (ret) - return ret; + /* Finally add anything with a pending flush (in order of retirement) */ + list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, list) { + if (obj_priv->pin_count) + continue; + if (mark_free(obj_priv, &unwind_list)) + goto found; + } + i915_for_each_active_object(obj_priv, &render_iter, &bsd_iter) { + if (! obj_priv->base.write_domain || obj_priv->pin_count) continue; - } - /* If we didn't have anything on the request list but there - * are buffers awaiting a flush, emit one and try again. - * When we wait on it, those buffers waiting for that flush - * will get moved to inactive. - */ - if (!list_empty(&dev_priv->mm.flushing_list)) { - struct drm_gem_object *obj = NULL; - struct drm_i915_gem_object *obj_priv; - - /* Find an object that we can immediately reuse */ - list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, list) { - obj = &obj_priv->base; - if (obj->size >= min_size) - break; - - obj = NULL; - } - - if (obj != NULL) { - uint32_t seqno; - - i915_gem_flush_ring(dev, - obj->write_domain, - obj->write_domain, - obj_priv->ring); - seqno = i915_add_request(dev, NULL, - obj->write_domain, - obj_priv->ring); - if (seqno == 0) - return -ENOMEM; - continue; - } + if (mark_free(obj_priv, &unwind_list)) + goto found; + } + + /* Nothing found, clean up and bail out! */ + list_for_each_entry(obj_priv, &unwind_list, evict_list) { + ret = drm_mm_scan_remove_block(obj_priv->gtt_space); + BUG_ON(ret); + } + + /* We expect the caller to unpin, evict all and try again, or give up. + * So calling i915_gem_evict_everything() is unnecessary. + */ + return -ENOSPC; + +found: + INIT_LIST_HEAD(&eviction_list); + list_for_each_entry_safe(obj_priv, tmp_obj_priv, + &unwind_list, evict_list) { + if (drm_mm_scan_remove_block(obj_priv->gtt_space)) { + /* drm_mm doesn't allow any other other operations while + * scanning, therefore store to be evicted objects on a + * temporary list. */ + list_move(&obj_priv->evict_list, &eviction_list); } + } - /* If we didn't do any of the above, there's no single buffer - * large enough to swap out for the new one, so just evict - * everything and start again. (This should be rare.) - */ - if (!list_empty(&dev_priv->mm.inactive_list)) - return i915_gem_evict_inactive(dev); - else - return i915_gem_evict_everything(dev); + /* Unbinding will emit any required flushes */ + list_for_each_entry_safe(obj_priv, tmp_obj_priv, + &eviction_list, evict_list) { +#if WATCH_LRU + DRM_INFO("%s: evicting %p\n", __func__, obj); +#endif + ret = i915_gem_object_unbind(&obj_priv->base); + if (ret) + return ret; } + + /* The just created free hole should be on the top of the free stack + * maintained by drm_mm, so this BUG_ON actually executes in O(1). + * Furthermore all accessed data has just recently been used, so it + * should be really fast, too. */ + BUG_ON(!drm_mm_search_free(&dev_priv->mm.gtt_space, min_size, + alignment, 0)); + + return 0; } int -- cgit v0.10.2 From 7d1c4804ae98cdee572d7d10d8a5deaa2e686285 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 21:45:03 +0100 Subject: drm/i915: Maintain LRU order of inactive objects upon access by CPU (v2) In order to reduce the penalty of fallbacks under memory pressure and to avoid a potential immediate ping-pong of evicting a mmaped buffer, we move the object to the tail of the inactive list when a page is freshly faulted or the object is moved into the CPU domain. We choose not to protect the CPU objects from casual eviction, preferring to keep the GPU active for as long as possible. v2: Daniel Vetter found a bug where I forgot that pinned objects are kept off the inactive list. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b5a7b00..8f3e0c1 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -57,6 +57,14 @@ static void i915_gem_free_object_tail(struct drm_gem_object *obj); static LIST_HEAD(shrink_list); static DEFINE_SPINLOCK(shrink_list_lock); +static inline bool +i915_gem_object_is_inactive(struct drm_i915_gem_object *obj_priv) +{ + return obj_priv->gtt_space && + !obj_priv->active && + obj_priv->pin_count == 0; +} + int i915_gem_do_init(struct drm_device *dev, unsigned long start, unsigned long end) { @@ -1036,6 +1044,11 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, ret = i915_gem_object_set_to_cpu_domain(obj, write_domain != 0); } + + /* Maintain LRU order of "inactive" objects */ + if (ret == 0 && i915_gem_object_is_inactive(obj_priv)) + list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list); + drm_gem_object_unreference(obj); mutex_unlock(&dev->struct_mutex); return ret; @@ -1137,6 +1150,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct drm_gem_object *obj = vma->vm_private_data; struct drm_device *dev = obj->dev; + drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); pgoff_t page_offset; unsigned long pfn; @@ -1166,6 +1180,9 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) goto unlock; } + if (i915_gem_object_is_inactive(obj_priv)) + list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list); + pfn = ((dev->agp->base + obj_priv->gtt_offset) >> PAGE_SHIFT) + page_offset; -- cgit v0.10.2 From e56660ddfb48ccc6777f31cb235db218e0cf5b83 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:26 +0100 Subject: drm/i915: Record error batch buffers using iomem Directly read the GTT mapping for the contents of the batch buffers rather than relying on possibly stale CPU caches. Also for completeness scan the flushing/inactive lists for the current buffers - we are collecting error state after all. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 854ab1e..5161cea 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -425,9 +425,11 @@ static struct drm_i915_error_object * i915_error_object_create(struct drm_device *dev, struct drm_gem_object *src) { + drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_error_object *dst; struct drm_i915_gem_object *src_priv; int page, page_count; + u32 reloc_offset; if (src == NULL) return NULL; @@ -442,18 +444,27 @@ i915_error_object_create(struct drm_device *dev, if (dst == NULL) return NULL; + reloc_offset = src_priv->gtt_offset; for (page = 0; page < page_count; page++) { - void *s, *d = kmalloc(PAGE_SIZE, GFP_ATOMIC); unsigned long flags; + void __iomem *s; + void *d; + d = kmalloc(PAGE_SIZE, GFP_ATOMIC); if (d == NULL) goto unwind; + local_irq_save(flags); - s = kmap_atomic(src_priv->pages[page], KM_IRQ0); - memcpy(d, s, PAGE_SIZE); - kunmap_atomic(s, KM_IRQ0); + s = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, + reloc_offset, + KM_IRQ0); + memcpy_fromio(d, s, PAGE_SIZE); + io_mapping_unmap_atomic(s, KM_IRQ0); local_irq_restore(flags); + dst->pages[page] = d; + + reloc_offset += PAGE_SIZE; } dst->page_count = page_count; dst->gtt_offset = src_priv->gtt_offset; @@ -613,18 +624,57 @@ static void i915_capture_error_state(struct drm_device *dev) if (batchbuffer[1] == NULL && error->acthd >= obj_priv->gtt_offset && - error->acthd < obj_priv->gtt_offset + obj->size && - batchbuffer[0] != obj) + error->acthd < obj_priv->gtt_offset + obj->size) batchbuffer[1] = obj; count++; } + /* Scan the other lists for completeness for those bizarre errors. */ + if (batchbuffer[0] == NULL || batchbuffer[1] == NULL) { + list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, list) { + struct drm_gem_object *obj = &obj_priv->base; + + if (batchbuffer[0] == NULL && + bbaddr >= obj_priv->gtt_offset && + bbaddr < obj_priv->gtt_offset + obj->size) + batchbuffer[0] = obj; + + if (batchbuffer[1] == NULL && + error->acthd >= obj_priv->gtt_offset && + error->acthd < obj_priv->gtt_offset + obj->size) + batchbuffer[1] = obj; + + if (batchbuffer[0] && batchbuffer[1]) + break; + } + } + if (batchbuffer[0] == NULL || batchbuffer[1] == NULL) { + list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) { + struct drm_gem_object *obj = &obj_priv->base; + + if (batchbuffer[0] == NULL && + bbaddr >= obj_priv->gtt_offset && + bbaddr < obj_priv->gtt_offset + obj->size) + batchbuffer[0] = obj; + + if (batchbuffer[1] == NULL && + error->acthd >= obj_priv->gtt_offset && + error->acthd < obj_priv->gtt_offset + obj->size) + batchbuffer[1] = obj; + + if (batchbuffer[0] && batchbuffer[1]) + break; + } + } /* We need to copy these to an anonymous buffer as the simplest * method to avoid being overwritten by userpace. */ error->batchbuffer[0] = i915_error_object_create(dev, batchbuffer[0]); - error->batchbuffer[1] = i915_error_object_create(dev, batchbuffer[1]); + if (batchbuffer[1] != batchbuffer[0]) + error->batchbuffer[1] = i915_error_object_create(dev, batchbuffer[1]); + else + error->batchbuffer[1] = NULL; /* Record the ringbuffer */ error->ringbuffer = i915_error_object_create(dev, -- cgit v0.10.2 From 2e88e40bed136a7b7cb1c77d8dc6bd181d0d2732 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:27 +0100 Subject: drm/i915/sdvo: Markup a few constant strings. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 1e31724..69cf724 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -50,7 +50,7 @@ #define IS_TV_OR_LVDS(c) (c->output_flag & (SDVO_TV_MASK | SDVO_LVDS_MASK)) -static char *tv_format_names[] = { +static const char *tv_format_names[] = { "NTSC_M" , "NTSC_J" , "NTSC_443", "PAL_B" , "PAL_D" , "PAL_G" , "PAL_H" , "PAL_I" , "PAL_M" , @@ -292,7 +292,7 @@ static bool intel_sdvo_write_byte(struct intel_sdvo *intel_sdvo, int addr, u8 ch /** Mapping of command numbers to names, for debug output */ static const struct _sdvo_cmd_name { u8 cmd; - char *name; + const char *name; } sdvo_cmd_names[] = { SDVO_CMD_NAME_ENTRY(SDVO_CMD_RESET), SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_DEVICE_CAPS), -- cgit v0.10.2 From 1d8e1c75ffa84400758aef9cc59298920b8801f9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:28 +0100 Subject: drm/i915: Enable aspect/centering panel fitting for Ironlake. v2: Hook in DP paths to keep FULLSCREEN panel fitting on eDP. Signed-off-by: Chris Wilson Reviewed-by: Zhenyu Wang Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 384fd45..5c8e534 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -19,6 +19,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \ intel_hdmi.o \ intel_sdvo.o \ intel_modes.o \ + intel_panel.o \ intel_i2c.o \ intel_fb.o \ intel_tv.o \ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6221f23..4b0ffb6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -614,6 +614,8 @@ typedef struct drm_i915_private { struct sdvo_device_mapping sdvo_mappings[2]; /* indicate whether the LVDS_BORDER should be enabled or not */ unsigned int lvds_border_bits; + /* Panel fitter placement and size for Ironlake+ */ + u32 pch_pf_pos, pch_pf_size; struct drm_crtc *plane_to_crtc_mapping[2]; struct drm_crtc *pipe_to_crtc_mapping[2]; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 24fbd0f..25e3866 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2005,15 +2005,13 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) /* Enable panel fitting for LVDS */ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) || HAS_eDP || intel_pch_has_edp(crtc)) { - temp = I915_READ(pf_ctl_reg); - I915_WRITE(pf_ctl_reg, temp | PF_ENABLE | PF_FILTER_MED_3x3); - - /* currently full aspect */ - I915_WRITE(pf_win_pos, 0); - - I915_WRITE(pf_win_size, - (dev_priv->panel_fixed_mode->hdisplay << 16) | - (dev_priv->panel_fixed_mode->vdisplay)); + if (dev_priv->pch_pf_size) { + temp = I915_READ(pf_ctl_reg); + I915_WRITE(pf_ctl_reg, temp | PF_ENABLE | PF_FILTER_MED_3x3); + I915_WRITE(pf_win_pos, dev_priv->pch_pf_pos); + I915_WRITE(pf_win_size, dev_priv->pch_pf_size); + } else + I915_WRITE(pf_ctl_reg, temp & ~PF_ENABLE); } /* Enable CPU pipe */ diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index c4c5868..cee5d9c 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -523,21 +523,9 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) && dev_priv->panel_fixed_mode) { - struct drm_display_mode *fixed_mode = dev_priv->panel_fixed_mode; - - adjusted_mode->hdisplay = fixed_mode->hdisplay; - adjusted_mode->hsync_start = fixed_mode->hsync_start; - adjusted_mode->hsync_end = fixed_mode->hsync_end; - adjusted_mode->htotal = fixed_mode->htotal; - - adjusted_mode->vdisplay = fixed_mode->vdisplay; - adjusted_mode->vsync_start = fixed_mode->vsync_start; - adjusted_mode->vsync_end = fixed_mode->vsync_end; - adjusted_mode->vtotal = fixed_mode->vtotal; - - adjusted_mode->clock = fixed_mode->clock; - drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); - + intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode); + intel_pch_panel_fitting(dev, DRM_MODE_SCALE_FULLSCREEN, + mode, adjusted_mode); /* * the mode->clock is used to calculate the Data&Link M/N * of the pipe. For the eDP the fixed clock should be used. @@ -572,8 +560,10 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, "count %d clock %d\n", intel_dp->link_bw, intel_dp->lane_count, adjusted_mode->clock); + return true; } + return false; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index a44b8cb..c552b06 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -186,6 +186,13 @@ extern bool intel_dpd_is_edp(struct drm_device *dev); extern void intel_edp_link_config (struct intel_encoder *, int *, int *); +extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, + struct drm_display_mode *adjusted_mode); +extern void intel_pch_panel_fitting(struct drm_device *dev, + int fitting_mode, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + extern int intel_panel_fitter_pipe (struct drm_device *dev); extern void intel_crtc_load_lut(struct drm_crtc *crtc); extern void intel_encoder_prepare (struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 312ac30..cb5821e 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -246,26 +246,20 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, /* If we don't have a panel mode, there is nothing we can do */ if (dev_priv->panel_fixed_mode == NULL) return true; + /* * We have timings from the BIOS for the panel, put them in * to the adjusted mode. The CRTC will be set up for this mode, * with the panel scaling set up to source from the H/VDisplay * of the original mode. */ - adjusted_mode->hdisplay = dev_priv->panel_fixed_mode->hdisplay; - adjusted_mode->hsync_start = - dev_priv->panel_fixed_mode->hsync_start; - adjusted_mode->hsync_end = - dev_priv->panel_fixed_mode->hsync_end; - adjusted_mode->htotal = dev_priv->panel_fixed_mode->htotal; - adjusted_mode->vdisplay = dev_priv->panel_fixed_mode->vdisplay; - adjusted_mode->vsync_start = - dev_priv->panel_fixed_mode->vsync_start; - adjusted_mode->vsync_end = - dev_priv->panel_fixed_mode->vsync_end; - adjusted_mode->vtotal = dev_priv->panel_fixed_mode->vtotal; - adjusted_mode->clock = dev_priv->panel_fixed_mode->clock; - drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); + intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode); + + if (HAS_PCH_SPLIT(dev)) { + intel_pch_panel_fitting(dev, intel_lvds->fitting_mode, + mode, adjusted_mode); + return true; + } /* Make sure pre-965s set dither correctly */ if (!IS_I965G(dev)) { @@ -278,10 +272,6 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, adjusted_mode->vdisplay == mode->vdisplay) goto out; - /* full screen scale for now */ - if (HAS_PCH_SPLIT(dev)) - goto out; - /* 965+ wants fuzzy fitting */ if (IS_I965G(dev)) pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) | @@ -293,10 +283,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, * to register description and PRM. * Change the value here to see the borders for debugging */ - if (!HAS_PCH_SPLIT(dev)) { - I915_WRITE(BCLRPAT_A, 0); - I915_WRITE(BCLRPAT_B, 0); - } + I915_WRITE(BCLRPAT_A, 0); + I915_WRITE(BCLRPAT_B, 0); switch (intel_lvds->fitting_mode) { case DRM_MODE_SCALE_CENTER: diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c new file mode 100644 index 0000000..e7f5299 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -0,0 +1,111 @@ +/* + * Copyright © 2006-2010 Intel Corporation + * Copyright (c) 2006 Dave Airlie + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * Dave Airlie + * Jesse Barnes + * Chris Wilson + */ + +#include "intel_drv.h" + +void +intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, + struct drm_display_mode *adjusted_mode) +{ + adjusted_mode->hdisplay = fixed_mode->hdisplay; + adjusted_mode->hsync_start = fixed_mode->hsync_start; + adjusted_mode->hsync_end = fixed_mode->hsync_end; + adjusted_mode->htotal = fixed_mode->htotal; + + adjusted_mode->vdisplay = fixed_mode->vdisplay; + adjusted_mode->vsync_start = fixed_mode->vsync_start; + adjusted_mode->vsync_end = fixed_mode->vsync_end; + adjusted_mode->vtotal = fixed_mode->vtotal; + + adjusted_mode->clock = fixed_mode->clock; + + drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); +} + +/* adjusted_mode has been preset to be the panel's fixed mode */ +void +intel_pch_panel_fitting(struct drm_device *dev, + int fitting_mode, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int x, y, width, height; + + x = y = width = height = 0; + + /* Native modes don't need fitting */ + if (adjusted_mode->hdisplay == mode->hdisplay && + adjusted_mode->vdisplay == mode->vdisplay) + goto done; + + switch (fitting_mode) { + case DRM_MODE_SCALE_CENTER: + width = mode->hdisplay; + height = mode->vdisplay; + x = (adjusted_mode->hdisplay - width + 1)/2; + y = (adjusted_mode->vdisplay - height + 1)/2; + break; + + case DRM_MODE_SCALE_ASPECT: + /* Scale but preserve the aspect ratio */ + { + u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay; + u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay; + if (scaled_width > scaled_height) { /* pillar */ + width = scaled_height / mode->vdisplay; + x = (adjusted_mode->hdisplay - width + 1) / 2; + y = 0; + height = adjusted_mode->vdisplay; + } else if (scaled_width < scaled_height) { /* letter */ + height = scaled_width / mode->hdisplay; + y = (adjusted_mode->vdisplay - height + 1) / 2; + x = 0; + width = adjusted_mode->hdisplay; + } else { + x = y = 0; + width = adjusted_mode->hdisplay; + height = adjusted_mode->vdisplay; + } + } + break; + + default: + case DRM_MODE_SCALE_FULLSCREEN: + x = y = 0; + width = adjusted_mode->hdisplay; + height = adjusted_mode->vdisplay; + break; + } + +done: + dev_priv->pch_pf_pos = (x << 16) | y; + dev_priv->pch_pf_size = (width << 16) | height; +} -- cgit v0.10.2 From 20a0945951705246278f43641bb13611c030e112 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:29 +0100 Subject: drm/i915: Write to display base last. Writing to the DSPBASE register triggers the double-buffered update to all the control registers, so always write it last in the update sequence. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 25e3866..874ae30 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1585,15 +1585,13 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, Start, Offset, x, y, crtc->fb->pitch); I915_WRITE(dspstride, crtc->fb->pitch); if (IS_I965G(dev)) { - I915_WRITE(dspbase, Offset); - I915_READ(dspbase); I915_WRITE(dspsurf, Start); - I915_READ(dspsurf); I915_WRITE(dsptileoff, (y << 16) | x); + I915_WRITE(dspbase, Offset); } else { I915_WRITE(dspbase, Start + Offset); - I915_READ(dspbase); } + POSTING_READ(dspbase); if ((IS_I965G(dev) || plane == 0)) intel_update_fbc(crtc, &crtc->mode); -- cgit v0.10.2 From ae9fed6b601821d70928797c56da0e2008ef840d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:30 +0100 Subject: drm/i915: Truncate the shmem backing pages on purge shmfs doesn't actually implement i_ops->truncate() so we were not immedatiately releasing the backing pages when shrinking the gfx cache under OOM. Instead use a combination of truncate_inode_pages() and i_ops->truncate_range() as is used by shmem_delete_inode(). Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 8f3e0c1..4130621 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1505,9 +1505,16 @@ i915_gem_object_truncate(struct drm_gem_object *obj) struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); struct inode *inode; + /* Our goal here is to return as much of the memory as + * is possible back to the system as we are called from OOM. + * To do this we must instruct the shmfs to drop all of its + * backing pages, *now*. Here we mirror the actions taken + * when by shmem_delete_inode() to release the backing store. + */ inode = obj->filp->f_path.dentry->d_inode; - if (inode->i_op->truncate) - inode->i_op->truncate (inode); + truncate_inode_pages(inode->i_mapping, 0); + if (inode->i_op->truncate_range) + inode->i_op->truncate_range(inode, 0, (loff_t)-1); obj_priv->madv = __I915_MADV_PURGED; } -- cgit v0.10.2 From 868dc58fbfda73493d62eae353b6b13649550e10 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:31 +0100 Subject: drm/i915/display: Add pipe/plane information to dpms debugging Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 874ae30..07f1996 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1956,7 +1956,7 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) case DRM_MODE_DPMS_ON: case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: - DRM_DEBUG_KMS("crtc %d dpms on\n", pipe); + DRM_DEBUG_KMS("crtc %d/%d dpms on\n", pipe, plane); if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { temp = I915_READ(PCH_LVDS); @@ -2142,10 +2142,10 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) intel_crtc_load_lut(crtc); intel_update_fbc(crtc, &crtc->mode); + break; - break; case DRM_MODE_DPMS_OFF: - DRM_DEBUG_KMS("crtc %d dpms off\n", pipe); + DRM_DEBUG_KMS("crtc %d/%d dpms off\n", pipe, plane); drm_vblank_off(dev, pipe); /* Disable display plane */ -- cgit v0.10.2 From 862daefcc9a1eb9ff3e4c3d8076c31535f710cf9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:32 +0100 Subject: drm/i915/opregion: Use ASLE response codes defined in 0.1 Within i915_opregion.c there are two blocks of semantically identical ASLE response codes defined. Only one of those matches the ACPI IGD OpRegion Specification 0.1, use those. Signed-off-by: Chris Wilson Acked-by: Matthew Garrett Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_opregion.c b/drivers/gpu/drm/i915/i915_opregion.c index 8fcc75c..ce402b2 100644 --- a/drivers/gpu/drm/i915/i915_opregion.c +++ b/drivers/gpu/drm/i915/i915_opregion.c @@ -114,10 +114,6 @@ struct opregion_asle { #define ASLE_REQ_MSK 0xf /* response bits of ASLE irq request */ -#define ASLE_ALS_ILLUM_FAIL (2<<10) -#define ASLE_BACKLIGHT_FAIL (2<<12) -#define ASLE_PFIT_FAIL (2<<14) -#define ASLE_PWM_FREQ_FAIL (2<<16) #define ASLE_ALS_ILLUM_FAILED (1<<10) #define ASLE_BACKLIGHT_FAILED (1<<12) #define ASLE_PFIT_FAILED (1<<14) @@ -155,11 +151,11 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) u32 max_backlight, level, shift; if (!(bclp & ASLE_BCLP_VALID)) - return ASLE_BACKLIGHT_FAIL; + return ASLE_BACKLIGHT_FAILED; bclp &= ASLE_BCLP_MSK; if (bclp < 0 || bclp > 255) - return ASLE_BACKLIGHT_FAIL; + return ASLE_BACKLIGHT_FAILED; blc_pwm_ctl = I915_READ(BLC_PWM_CTL); blc_pwm_ctl2 = I915_READ(BLC_PWM_CTL2); @@ -211,7 +207,7 @@ static u32 asle_set_pfit(struct drm_device *dev, u32 pfit) /* Panel fitting is currently controlled by the X code, so this is a noop until modesetting support works fully */ if (!(pfit & ASLE_PFIT_VALID)) - return ASLE_PFIT_FAIL; + return ASLE_PFIT_FAILED; return 0; } -- cgit v0.10.2 From debcaddcbd92387137b87f2c1c640571753915e0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:33 +0100 Subject: drm/i915: Update watermarks for Ironlake after dpms changes Previously, we only remembered to update the watermarks for i9xx, and incorrectly assumed that the crtc->enabled flag was valid at that point in the dpms cycle. Note that on my x201s this makes a SR bug on pipe 1 much easier to hit. (Since before this patch when disabling pipe 0, we either didn't update the watermarks at all, or when we did we still thought we had two pipes enabled and so disabled SR.) References: Bug 28969 - [Arrandale] Screen flickers, suspect Self-Refresh https://bugs.freedesktop.org/show_bug.cgi?id=28969 Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 07f1996..1eae234 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2369,8 +2369,6 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) case DRM_MODE_DPMS_ON: case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: - intel_update_watermarks(dev); - /* Enable the DPLL */ temp = I915_READ(dpll_reg); if ((temp & DPLL_VCO_ENABLE) == 0) { @@ -2410,8 +2408,6 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) intel_crtc_dpms_overlay(intel_crtc, true); break; case DRM_MODE_DPMS_OFF: - intel_update_watermarks(dev); - /* Give the overlay scaler a chance to disable if it's on this pipe */ intel_crtc_dpms_overlay(intel_crtc, false); drm_vblank_off(dev, pipe); @@ -2476,12 +2472,26 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) int pipe = intel_crtc->pipe; bool enabled; - dev_priv->display.dpms(crtc, mode); - intel_crtc->dpms_mode = mode; - intel_crtc->cursor_on = mode == DRM_MODE_DPMS_ON; - intel_crtc_update_cursor(crtc); + + /* When switching on the display, ensure that SR is disabled + * with multiple pipes prior to enabling to new pipe. + * + * When switching off the display, make sure the cursor is + * properly hidden prior to disabling the pipe. + */ + if (mode == DRM_MODE_DPMS_ON) + intel_update_watermarks(dev); + else + intel_crtc_update_cursor(crtc); + + dev_priv->display.dpms(crtc, mode); + + if (mode == DRM_MODE_DPMS_ON) + intel_crtc_update_cursor(crtc); + else + intel_update_watermarks(dev); if (!dev->primary->master) return; @@ -3362,12 +3372,11 @@ static void ironlake_update_wm(struct drm_device *dev, int planea_clock, int line_count; int planea_htotal = 0, planeb_htotal = 0; struct drm_crtc *crtc; - struct intel_crtc *intel_crtc; /* Need htotal for all active display plane */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - intel_crtc = to_intel_crtc(crtc); - if (crtc->enabled) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + if (intel_crtc->dpms_mode == DRM_MODE_DPMS_ON) { if (intel_crtc->plane == 0) planea_htotal = crtc->mode.htotal; else @@ -3527,7 +3536,6 @@ static void intel_update_watermarks(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; - struct intel_crtc *intel_crtc; int sr_hdisplay = 0; unsigned long planea_clock = 0, planeb_clock = 0, sr_clock = 0; int enabled = 0, pixel_size = 0; @@ -3538,8 +3546,8 @@ static void intel_update_watermarks(struct drm_device *dev) /* Get the clock config from both planes */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - intel_crtc = to_intel_crtc(crtc); - if (crtc->enabled) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + if (intel_crtc->dpms_mode == DRM_MODE_DPMS_ON) { enabled++; if (intel_crtc->plane == 0) { DRM_DEBUG_KMS("plane A (pipe %d) clock: %d\n", -- cgit v0.10.2 From dd785e35cb3c430c2290d351e67715864f7e5db5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:34 +0100 Subject: drm/i915/ringbuffer: Set ring->gem_buffer = NULL on init unwind The cleanup path for early abort failed to nullify the gem_buffer. The likely consequence of this is zero, since a failure here should mean aborting the module load. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 3a02425..7823b96 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -608,9 +608,10 @@ err: int intel_init_ring_buffer(struct drm_device *dev, struct intel_ring_buffer *ring) { - int ret; struct drm_i915_gem_object *obj_priv; struct drm_gem_object *obj; + int ret; + ring->dev = dev; if (I915_NEED_GFX_HWS(dev)) { @@ -623,16 +624,14 @@ int intel_init_ring_buffer(struct drm_device *dev, if (obj == NULL) { DRM_ERROR("Failed to allocate ringbuffer\n"); ret = -ENOMEM; - goto cleanup; + goto err_hws; } ring->gem_object = obj; ret = i915_gem_object_pin(obj, ring->alignment); - if (ret != 0) { - drm_gem_object_unreference(obj); - goto cleanup; - } + if (ret) + goto err_unref; obj_priv = to_intel_bo(obj); ring->map.size = ring->size; @@ -644,18 +643,14 @@ int intel_init_ring_buffer(struct drm_device *dev, drm_core_ioremap_wc(&ring->map, dev); if (ring->map.handle == NULL) { DRM_ERROR("Failed to map ringbuffer.\n"); - i915_gem_object_unpin(obj); - drm_gem_object_unreference(obj); ret = -EINVAL; - goto cleanup; + goto err_unpin; } ring->virtual_start = ring->map.handle; ret = ring->init(dev, ring); - if (ret != 0) { - intel_cleanup_ring_buffer(dev, ring); - return ret; - } + if (ret) + goto err_unmap; if (!drm_core_check_feature(dev, DRIVER_MODESET)) i915_kernel_lost_context(dev); @@ -669,7 +664,15 @@ int intel_init_ring_buffer(struct drm_device *dev, INIT_LIST_HEAD(&ring->active_list); INIT_LIST_HEAD(&ring->request_list); return ret; -cleanup: + +err_unmap: + drm_core_ioremapfree(&ring->map, dev); +err_unpin: + i915_gem_object_unpin(obj); +err_unref: + drm_gem_object_unreference(obj); + ring->gem_object = NULL; +err_hws: cleanup_status_page(dev, ring); return ret; } -- cgit v0.10.2 From 913d8d110078788c14812dce8bb62c37946821d2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:35 +0100 Subject: drm/i915: Ensure that while(INREG()) are bounded (v2) Add a new macro, wait_for, to simplify the act of waiting on a register to change state. wait_for() takes three arguments, the condition to inspect on every loop, the maximum amount of time to wait and whether to yield the cpu for a length of time after each check. v2: Upgrade failure messages to DRM_ERROR on the suggestion of Eric Anholt. We do not expect to hit these conditions as they reflect programming errors, so if we do we want to be notified. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index cfcf854..c43176d 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -185,8 +185,9 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) DRM_DEBUG_KMS("pch crt adpa 0x%x", adpa); I915_WRITE(PCH_ADPA, adpa); - while ((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) != 0) - ; + if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0, + 1000, 1)) + DRM_ERROR("timed out waiting for FORCE_TRIGGER"); if (HAS_PCH_CPT(dev)) { I915_WRITE(PCH_ADPA, temp); @@ -237,17 +238,13 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) hotplug_en |= CRT_HOTPLUG_FORCE_DETECT; for (i = 0; i < tries ; i++) { - unsigned long timeout; /* turn on the FORCE_DETECT */ I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); - timeout = jiffies + msecs_to_jiffies(1000); /* wait for FORCE_DETECT to go off */ - do { - if (!(I915_READ(PORT_HOTPLUG_EN) & - CRT_HOTPLUG_FORCE_DETECT)) - break; - msleep(1); - } while (time_after(timeout, jiffies)); + if (wait_for((I915_READ(PORT_HOTPLUG_EN) & + CRT_HOTPLUG_FORCE_DETECT) == 0, + 1000, 1)) + DRM_ERROR("timed out waiting for FORCE_DETECT to go off"); } stat = I915_READ(PORT_HOTPLUG_STAT); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1eae234..0bf683d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1037,7 +1037,6 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) void i8xx_disable_fbc(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long timeout = jiffies + msecs_to_jiffies(1); u32 fbc_ctl; if (!I915_HAS_FBC(dev)) @@ -1052,12 +1051,9 @@ void i8xx_disable_fbc(struct drm_device *dev) I915_WRITE(FBC_CONTROL, fbc_ctl); /* Wait for compressing bit to clear */ - while (I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) { - if (time_after(jiffies, timeout)) { - DRM_DEBUG_DRIVER("FBC idle timed out\n"); - break; - } - ; /* do nothing */ + if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10, 0)) { + DRM_DEBUG_KMS("FBC idle timed out\n"); + return; } intel_wait_for_vblank(dev); @@ -1943,7 +1939,6 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B; int trans_dpll_sel = (pipe == 0) ? 0 : 1; u32 temp; - int n; u32 pipe_bpc; temp = I915_READ(pipeconf_reg); @@ -2134,9 +2129,8 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) I915_WRITE(transconf_reg, temp | TRANS_ENABLE); I915_READ(transconf_reg); - while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0) - ; - + if (wait_for(I915_READ(transconf_reg) & TRANS_STATE_ENABLE, 10, 0)) + DRM_ERROR("failed to enable transcoder\n"); } intel_crtc_load_lut(crtc); @@ -2167,20 +2161,10 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) temp = I915_READ(pipeconf_reg); if ((temp & PIPEACONF_ENABLE) != 0) { I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE); - I915_READ(pipeconf_reg); - n = 0; + /* wait for cpu pipe off, pipe state */ - while ((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) != 0) { - n++; - if (n < 60) { - udelay(500); - continue; - } else { - DRM_DEBUG_KMS("pipe %d off delay\n", - pipe); - break; - } - } + if (wait_for((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) == 0, 50, 1)) + DRM_ERROR("failed to turn off cpu pipe\n"); } else DRM_DEBUG_KMS("crtc %d is disabled\n", pipe); @@ -2241,20 +2225,10 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) temp = I915_READ(transconf_reg); if ((temp & TRANS_ENABLE) != 0) { I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE); - I915_READ(transconf_reg); - n = 0; + /* wait for PCH transcoder off, transcoder state */ - while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) != 0) { - n++; - if (n < 60) { - udelay(500); - continue; - } else { - DRM_DEBUG_KMS("transcoder %d off " - "delay\n", pipe); - break; - } - } + if (wait_for((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0, 50, 1)) + DRM_ERROR("failed to disable transcoder\n"); } temp = I915_READ(transconf_reg); @@ -5521,7 +5495,6 @@ void ironlake_enable_drps(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; u32 rgvmodectl = I915_READ(MEMMODECTL); u8 fmax, fmin, fstart, vstart; - int i = 0; /* 100ms RC evaluation intervals */ I915_WRITE(RCUPEI, 100000); @@ -5565,13 +5538,8 @@ void ironlake_enable_drps(struct drm_device *dev) rgvmodectl |= MEMMODE_SWMODE_EN; I915_WRITE(MEMMODECTL, rgvmodectl); - while (I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) { - if (i++ > 100) { - DRM_ERROR("stuck trying to change perf mode\n"); - break; - } - msleep(1); - } + if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 1, 0)) + DRM_ERROR("stuck trying to change perf mode\n"); msleep(1); ironlake_set_drps(dev, fstart); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index cee5d9c..c6629bd 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -759,22 +759,18 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, static void ironlake_edp_panel_on (struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long timeout = jiffies + msecs_to_jiffies(5000); - u32 pp, pp_status; + u32 pp; - pp_status = I915_READ(PCH_PP_STATUS); - if (pp_status & PP_ON) + if (I915_READ(PCH_PP_STATUS) & PP_ON) return; pp = I915_READ(PCH_PP_CONTROL); pp |= PANEL_UNLOCK_REGS | POWER_TARGET_ON; I915_WRITE(PCH_PP_CONTROL, pp); - do { - pp_status = I915_READ(PCH_PP_STATUS); - } while (((pp_status & PP_ON) == 0) && !time_after(jiffies, timeout)); - if (time_after(jiffies, timeout)) - DRM_DEBUG_KMS("panel on wait timed out: 0x%08x\n", pp_status); + if (wait_for(I915_READ(PCH_PP_STATUS) & PP_ON, 5000, 10)) + DRM_ERROR("panel on wait timed out: 0x%08x\n", + I915_READ(PCH_PP_STATUS)); pp &= ~(PANEL_UNLOCK_REGS | EDP_FORCE_VDD); I915_WRITE(PCH_PP_CONTROL, pp); @@ -783,18 +779,15 @@ static void ironlake_edp_panel_on (struct drm_device *dev) static void ironlake_edp_panel_off (struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long timeout = jiffies + msecs_to_jiffies(5000); - u32 pp, pp_status; + u32 pp; pp = I915_READ(PCH_PP_CONTROL); pp &= ~POWER_TARGET_ON; I915_WRITE(PCH_PP_CONTROL, pp); - do { - pp_status = I915_READ(PCH_PP_STATUS); - } while ((pp_status & PP_ON) && !time_after(jiffies, timeout)); - if (time_after(jiffies, timeout)) - DRM_DEBUG_KMS("panel off wait timed out\n"); + if (wait_for((I915_READ(PCH_PP_STATUS) & PP_ON) == 0, 5000, 10)) + DRM_ERROR("panel off wait timed out: 0x%08x\n", + I915_READ(PCH_PP_STATUS)); /* Make sure VDD is enabled so DP AUX will work */ pp |= EDP_FORCE_VDD; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index c552b06..2a3eaaf 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -32,6 +32,20 @@ #include "drm_crtc.h" #include "drm_crtc_helper.h" + +#define wait_for(COND, MS, W) ({ \ + unsigned long timeout__ = jiffies + msecs_to_jiffies(MS); \ + int ret__ = 0; \ + while (! (COND)) { \ + if (time_after(jiffies, timeout__)) { \ + ret__ = -ETIMEDOUT; \ + break; \ + } \ + if (W) msleep(W); \ + } \ + ret__; \ +}) + /* * Display related stuff */ diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index cb5821e..b819c10 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -96,7 +96,7 @@ static u32 intel_lvds_get_max_backlight(struct drm_device *dev) static void intel_lvds_set_power(struct drm_device *dev, bool on) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 pp_status, ctl_reg, status_reg, lvds_reg; + u32 ctl_reg, status_reg, lvds_reg; if (HAS_PCH_SPLIT(dev)) { ctl_reg = PCH_PP_CONTROL; @@ -114,9 +114,8 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on) I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON); - do { - pp_status = I915_READ(status_reg); - } while ((pp_status & PP_ON) == 0); + if (wait_for(I915_READ(status_reg) & PP_ON, 1000, 0)) + DRM_ERROR("timed out waiting to enable LVDS pipe"); intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle); } else { @@ -124,9 +123,8 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on) I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON); - do { - pp_status = I915_READ(status_reg); - } while (pp_status & PP_ON); + if (wait_for((I915_READ(status_reg) & PP_ON) == 0, 1000, 0)) + DRM_ERROR("timed out waiting for LVDS pipe to turn off"); I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN); POSTING_READ(lvds_reg); -- cgit v0.10.2 From 5ddb954b9ee50824977d2931e0ff58b3050b337d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:36 +0100 Subject: drm/i915/edp: Flush the write before waiting for PLLs Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0bf683d..2a32a7b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1665,6 +1665,7 @@ static void ironlake_enable_pll_edp (struct drm_crtc *crtc) dpa_ctl = I915_READ(DP_A); dpa_ctl |= DP_PLL_ENABLE; I915_WRITE(DP_A, dpa_ctl); + POSTING_READ(DP_A); udelay(200); } -- cgit v0.10.2 From c27ba48e629d2a845f26489fcddc9912673711e7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:37 +0100 Subject: drm/i915: FBC is updated within set_base() so remove second call in mode_set() The FBC is dependent upon a few details of the framebuffer so it is required to be updated within set_base(), so remove the redundant call from mode_set(). Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2a32a7b..41b4caf 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4171,9 +4171,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, /* Flush the plane changes */ ret = intel_pipe_set_base(crtc, x, y, old_fb); - if ((IS_I965G(dev) || plane == 0)) - intel_update_fbc(crtc, &crtc->mode); - intel_update_watermarks(dev); drm_vblank_post_modeset(dev, pipe); -- cgit v0.10.2 From 560b85bb750c3c539641993dd508b61260c9e874 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:38 +0100 Subject: drm/i915: Only update i845/i865 CURBASE when disabled (v2) The i845 and i865 have a peculiarlity in that CURBASE is not the trigger for the vsync update of the cursor registers but instead the modification of that register is prohibited whilst the cursor is enabled. Reorder the write sequence for CURPOS, CURCNTR and CURBASE on i845 to i865 to match. v2: Remove the checks for i845/i865 from within i9xx_cursor_update() Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 41b4caf..6490d8b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4204,6 +4204,62 @@ void intel_crtc_load_lut(struct drm_crtc *crtc) } } +static void i845_update_cursor(struct drm_crtc *crtc, u32 base) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + bool visible = base != 0; + u32 cntl; + + if (intel_crtc->cursor_visible == visible) + return; + + cntl = I915_READ(CURACNTR); + if (visible) { + /* On these chipsets we can only modify the base whilst + * the cursor is disabled. + */ + I915_WRITE(CURABASE, base); + + cntl &= ~(CURSOR_FORMAT_MASK); + /* XXX width must be 64, stride 256 => 0x00 << 28 */ + cntl |= CURSOR_ENABLE | + CURSOR_GAMMA_ENABLE | + CURSOR_FORMAT_ARGB; + } else + cntl &= ~(CURSOR_ENABLE | CURSOR_GAMMA_ENABLE); + I915_WRITE(CURACNTR, cntl); + + intel_crtc->cursor_visible = visible; +} + +static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + bool visible = base != 0; + + if (intel_crtc->cursor_visible != visible) { + uint32_t cntl = I915_READ(pipe == 0 ? CURACNTR : CURBCNTR); + if (base) { + cntl &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT); + cntl |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE; + cntl |= pipe << 28; /* Connect to correct pipe */ + } else { + cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE); + cntl |= CURSOR_MODE_DISABLE; + } + I915_WRITE(pipe == 0 ? CURACNTR : CURBCNTR, cntl); + + intel_crtc->cursor_visible = visible; + } + /* and commit changes on next vblank */ + I915_WRITE(pipe == 0 ? CURABASE : CURBBASE, base); +} + /* If no-part of the cursor is visible on the framebuffer, then the GPU may hang... */ static void intel_crtc_update_cursor(struct drm_crtc *crtc) { @@ -4213,7 +4269,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc) int pipe = intel_crtc->pipe; int x = intel_crtc->cursor_x; int y = intel_crtc->cursor_y; - uint32_t base, pos; + u32 base, pos; bool visible; pos = 0; @@ -4247,37 +4303,14 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc) pos |= y << CURSOR_Y_SHIFT; visible = base != 0; - if (!visible && !intel_crtc->cursor_visble) + if (!visible && !intel_crtc->cursor_visible) return; I915_WRITE(pipe == 0 ? CURAPOS : CURBPOS, pos); - if (intel_crtc->cursor_visble != visible) { - uint32_t cntl = I915_READ(pipe == 0 ? CURACNTR : CURBCNTR); - if (base) { - /* Hooray for CUR*CNTR differences */ - if (IS_MOBILE(dev) || IS_I9XX(dev)) { - cntl &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT); - cntl |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE; - cntl |= pipe << 28; /* Connect to correct pipe */ - } else { - cntl &= ~(CURSOR_FORMAT_MASK); - cntl |= CURSOR_ENABLE; - cntl |= CURSOR_FORMAT_ARGB | CURSOR_GAMMA_ENABLE; - } - } else { - if (IS_MOBILE(dev) || IS_I9XX(dev)) { - cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE); - cntl |= CURSOR_MODE_DISABLE; - } else { - cntl &= ~(CURSOR_ENABLE | CURSOR_GAMMA_ENABLE); - } - } - I915_WRITE(pipe == 0 ? CURACNTR : CURBCNTR, cntl); - - intel_crtc->cursor_visble = visible; - } - /* and commit changes on next vblank */ - I915_WRITE(pipe == 0 ? CURABASE : CURBBASE, base); + if (IS_845G(dev) || IS_I865G(dev)) + i845_update_cursor(crtc, base); + else + i9xx_update_cursor(crtc, base); if (visible) intel_mark_busy(dev, to_intel_framebuffer(crtc->fb)->obj); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2a3eaaf..6ba56e1 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -168,7 +168,7 @@ struct intel_crtc { uint32_t cursor_addr; int16_t cursor_x, cursor_y; int16_t cursor_width, cursor_height; - bool cursor_visble, cursor_on; + bool cursor_visible, cursor_on; }; #define to_intel_crtc(x) container_of(x, struct intel_crtc, base) -- cgit v0.10.2 From 6eeefaf3c86b8937db8ad930c48bfb592fc5e32e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:39 +0100 Subject: drm/i915: Apply i830 errata for cursor alignment i830 requires 32bpp cursors to be aligned to 16KB, so we have to expose the alignment parameter to i915_gem_attach_phys_object(). Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4b0ffb6..8df6ac7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1000,7 +1000,9 @@ int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write); int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj); int i915_gem_attach_phys_object(struct drm_device *dev, - struct drm_gem_object *obj, int id); + struct drm_gem_object *obj, + int id, + int align); void i915_gem_detach_phys_object(struct drm_device *dev, struct drm_gem_object *obj); void i915_gem_free_all_phys_object(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4130621..b4b25e1 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4674,7 +4674,7 @@ i915_gem_load(struct drm_device *dev) * e.g. for cursor + overlay regs */ int i915_gem_init_phys_object(struct drm_device *dev, - int id, int size) + int id, int size, int align) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_phys_object *phys_obj; @@ -4689,7 +4689,7 @@ int i915_gem_init_phys_object(struct drm_device *dev, phys_obj->id = id; - phys_obj->handle = drm_pci_alloc(dev, size, 0); + phys_obj->handle = drm_pci_alloc(dev, size, align); if (!phys_obj->handle) { ret = -ENOMEM; goto kfree_obj; @@ -4771,7 +4771,9 @@ out: int i915_gem_attach_phys_object(struct drm_device *dev, - struct drm_gem_object *obj, int id) + struct drm_gem_object *obj, + int id, + int align) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv; @@ -4790,11 +4792,10 @@ i915_gem_attach_phys_object(struct drm_device *dev, i915_gem_detach_phys_object(dev, obj); } - /* create a new object */ if (!dev_priv->mm.phys_objs[id - 1]) { ret = i915_gem_init_phys_object(dev, id, - obj->size); + obj->size, align); if (ret) { DRM_ERROR("failed to init phys object %d size: %zu\n", id, obj->size); goto out; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6490d8b..53f3a98 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4375,8 +4375,10 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, addr = obj_priv->gtt_offset; } else { + int align = IS_I830(dev) ? 16 * 1024 : 256; ret = i915_gem_attach_phys_object(dev, bo, - (intel_crtc->pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1); + (intel_crtc->pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1, + align); if (ret) { DRM_ERROR("failed to attach phys object\n"); goto fail_locked; diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 9ae61aa..4f00390 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -1367,7 +1367,8 @@ void intel_setup_overlay(struct drm_device *dev) overlay->flip_addr = overlay->reg_bo->gtt_offset; } else { ret = i915_gem_attach_phys_object(dev, reg_bo, - I915_GEM_PHYS_OVERLAY_REGS); + I915_GEM_PHYS_OVERLAY_REGS, + 0); if (ret) { DRM_ERROR("failed to attach phys overlay regs\n"); goto out_free_bo; -- cgit v0.10.2 From e78d73b16bcde921c9cf458d2e4de8e4fc2518f3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 14:18:47 +0100 Subject: drm/i915: Wake-up wait_request() from elapsed hang-check (v2) If our watchdog fires and we see that the GPU is idle, but that we are still waiting on an interrupt, forcibly wake-up the waiter. i915_do_wait_request() should not be racy, yet there are persistent reports that 945GM hangs whilst the GPU is idle. This implies that the hardware is not quite as coherent as the documentation claims - a write followed by a flush is supposed to be coherent in main memory before the flush is retired and the irq is emitted. This seems to be a sensible and elegant guard to force the wait to timeout. v2: Daniel Vetter pointed out that a warning would be useful to explain why the machine appeared to stall. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 5161cea..69a36fc 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1304,6 +1304,16 @@ void i915_hangcheck_elapsed(unsigned long data) &dev_priv->render_ring), i915_get_tail_request(dev)->seqno)) { dev_priv->hangcheck_count = 0; + + /* Issue a wake-up to catch stuck h/w. */ + if (dev_priv->render_ring.waiting_gem_seqno | + dev_priv->bsd_ring.waiting_gem_seqno) { + DRM_ERROR("Hangcheck timer elapsed... GPU idle, missed IRQ.\n"); + if (dev_priv->render_ring.waiting_gem_seqno) + DRM_WAKEUP(&dev_priv->render_ring.irq_queue); + if (dev_priv->bsd_ring.waiting_gem_seqno) + DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue); + } return; } -- cgit v0.10.2 From 1cafd34731cd14e5a72edaf0f41717c8126cfce9 Mon Sep 17 00:00:00 2001 From: Zou Nan hai Date: Fri, 25 Jun 2010 13:40:24 +0800 Subject: drm/i915 invalidate indirect state pointers at end of ring exec This is required by the spec, and without this some 3D programs will hang after resume from RC6 we enable that. Signed-off-by: Zou Nan hai Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index f19ffe8..44af317 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -499,6 +499,13 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev, } } + + if (IS_G4X(dev) || IS_IRONLAKE(dev)) { + BEGIN_LP_RING(2); + OUT_RING(MI_FLUSH | MI_NO_WRITE_FLUSH | MI_INVALIDATE_ISP); + OUT_RING(MI_NOOP); + ADVANCE_LP_RING(); + } i915_emit_breadcrumb(dev); return 0; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 97a35a4..21fd657 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -170,6 +170,7 @@ #define MI_NO_WRITE_FLUSH (1 << 2) #define MI_SCENE_COUNT (1 << 3) /* just increment scene count */ #define MI_END_SCENE (1 << 4) /* flush binner and incr scene count */ +#define MI_INVALIDATE_ISP (1 << 5) /* invalidate indirect state pointers */ #define MI_BATCH_BUFFER_END MI_INSTR(0x0a, 0) #define MI_REPORT_HEAD MI_INSTR(0x07, 0) #define MI_OVERLAY_FLIP MI_INSTR(0x11,0) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 7823b96..51e9c9e7 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -535,7 +535,16 @@ render_ring_dispatch_gem_execbuffer(struct drm_device *dev, intel_ring_advance(dev, ring); } + if (IS_G4X(dev) || IS_IRONLAKE(dev)) { + intel_ring_begin(dev, ring, 2); + intel_ring_emit(dev, ring, MI_FLUSH | + MI_NO_WRITE_FLUSH | + MI_INVALIDATE_ISP ); + intel_ring_emit(dev, ring, MI_NOOP); + intel_ring_advance(dev, ring); + } /* XXX breadcrumb */ + return 0; } -- cgit v0.10.2 From aa40d6bbb9cf88f3fb296a57e046a52e9a68ab72 Mon Sep 17 00:00:00 2001 From: Zou Nan hai Date: Fri, 25 Jun 2010 13:40:23 +0800 Subject: drm/i915: Set up a render context on Ironlake RC6 power state requires a logical render context in place for saving render context. Signed-off-by: Zou Nan hai Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8df6ac7..047cd7c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -254,6 +254,7 @@ typedef struct drm_i915_private { drm_local_map_t hws_map; struct drm_gem_object *seqno_obj; struct drm_gem_object *pwrctx; + struct drm_gem_object *renderctx; struct resource mch_res; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 21fd657..a63e9a1 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -181,6 +181,12 @@ #define MI_DISPLAY_FLIP MI_INSTR(0x14, 2) #define MI_DISPLAY_FLIP_I915 MI_INSTR(0x14, 1) #define MI_DISPLAY_FLIP_PLANE(n) ((n) << 20) +#define MI_SET_CONTEXT MI_INSTR(0x18, 0) +#define MI_MM_SPACE_GTT (1<<8) +#define MI_MM_SPACE_PHYSICAL (0<<8) +#define MI_SAVE_EXT_STATE_EN (1<<3) +#define MI_RESTORE_EXT_STATE_EN (1<<2) +#define MI_RESTORE_INHIBIT (1<<0) #define MI_STORE_DWORD_IMM MI_INSTR(0x20, 1) #define MI_MEM_VIRTUAL (1 << 22) /* 965+ only */ #define MI_STORE_DWORD_INDEX MI_INSTR(0x21, 1) @@ -1101,6 +1107,11 @@ #define PEG_BAND_GAP_DATA 0x14d68 /* + * Logical Context regs + */ +#define CCID 0x2180 +#define CCID_EN (1<<0) +/* * Overlay regs */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 53f3a98..4668e9b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5466,37 +5466,37 @@ static const struct drm_mode_config_funcs intel_mode_funcs = { }; static struct drm_gem_object * -intel_alloc_power_context(struct drm_device *dev) +intel_alloc_context_page(struct drm_device *dev) { - struct drm_gem_object *pwrctx; + struct drm_gem_object *ctx; int ret; - pwrctx = i915_gem_alloc_object(dev, 4096); - if (!pwrctx) { + ctx = i915_gem_alloc_object(dev, 4096); + if (!ctx) { DRM_DEBUG("failed to alloc power context, RC6 disabled\n"); return NULL; } mutex_lock(&dev->struct_mutex); - ret = i915_gem_object_pin(pwrctx, 4096); + ret = i915_gem_object_pin(ctx, 4096); if (ret) { DRM_ERROR("failed to pin power context: %d\n", ret); goto err_unref; } - ret = i915_gem_object_set_to_gtt_domain(pwrctx, 1); + ret = i915_gem_object_set_to_gtt_domain(ctx, 1); if (ret) { DRM_ERROR("failed to set-domain on power context: %d\n", ret); goto err_unpin; } mutex_unlock(&dev->struct_mutex); - return pwrctx; + return ctx; err_unpin: - i915_gem_object_unpin(pwrctx); + i915_gem_object_unpin(ctx); err_unref: - drm_gem_object_unreference(pwrctx); + drm_gem_object_unreference(ctx); mutex_unlock(&dev->struct_mutex); return NULL; } @@ -5796,6 +5796,29 @@ void intel_init_clock_gating(struct drm_device *dev) * GPU can automatically power down the render unit if given a page * to save state. */ + if (IS_IRONLAKE_M(dev)) { + if (dev_priv->renderctx == NULL) + dev_priv->renderctx = intel_alloc_context_page(dev); + if (dev_priv->renderctx) { + struct drm_i915_gem_object *obj_priv; + obj_priv = to_intel_bo(dev_priv->renderctx); + if (obj_priv) { + BEGIN_LP_RING(4); + OUT_RING(MI_SET_CONTEXT); + OUT_RING(obj_priv->gtt_offset | + MI_MM_SPACE_GTT | + MI_SAVE_EXT_STATE_EN | + MI_RESTORE_EXT_STATE_EN | + MI_RESTORE_INHIBIT); + OUT_RING(MI_NOOP); + OUT_RING(MI_FLUSH); + ADVANCE_LP_RING(); + } + } else + DRM_DEBUG_KMS("Failed to allocate render context." + "Disable RC6\n"); + } + if (I915_HAS_RC6(dev) && drm_core_check_feature(dev, DRIVER_MODESET)) { struct drm_i915_gem_object *obj_priv = NULL; @@ -5804,7 +5827,7 @@ void intel_init_clock_gating(struct drm_device *dev) } else { struct drm_gem_object *pwrctx; - pwrctx = intel_alloc_power_context(dev); + pwrctx = intel_alloc_context_page(dev); if (pwrctx) { dev_priv->pwrctx = pwrctx; obj_priv = to_intel_bo(pwrctx); @@ -6062,6 +6085,16 @@ void intel_modeset_cleanup(struct drm_device *dev) if (dev_priv->display.disable_fbc) dev_priv->display.disable_fbc(dev); + if (dev_priv->renderctx) { + struct drm_i915_gem_object *obj_priv; + + obj_priv = to_intel_bo(dev_priv->renderctx); + I915_WRITE(CCID, obj_priv->gtt_offset &~ CCID_EN); + I915_READ(CCID); + i915_gem_object_unpin(dev_priv->renderctx); + drm_gem_object_unreference(dev_priv->renderctx); + } + if (dev_priv->pwrctx) { struct drm_i915_gem_object *obj_priv; -- cgit v0.10.2 From 8545423a912cf500009cbadfae57f706cf2b28e8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 8 Aug 2010 14:28:23 +0100 Subject: drm/i915/sdvo: Only set is_lvds if we have a valid fixed mode. If we have failed to ascertain the fixed mode for the LVDS panel, then trust the pixel clock ranges reported for the connection when determing valid modes. This makes intel_sdvo_mode_valid() consistent with intel_lvds_mode_valid() which is also a no-op is there is no fixed mode defined. (Since the mode is both validated by SDVO and LVDS, why are checking against an LVDS fixed mode in SDVO...) By only defining is_lvds to be true when we actually have an LVDS output with a fixed mode, we avoid various potential NULL deferences where the assumption is made that all LVDS outputs have a fixed mode. References: Bug 29449 - [Q35] failure to read EDID/vbios for LVDS, no mode => no output https://bugs.freedesktop.org/show_bug.cgi?id=29449 The primary failure in this bug is not finding the EDID and determining the correct fixed panel mode. However, this patch should fix the secondary issue of not enabling any of the standard modes for the panel either. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 69cf724..5c765bb 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1274,10 +1274,7 @@ static int intel_sdvo_mode_valid(struct drm_connector *connector, if (intel_sdvo->pixel_clock_max < mode->clock) return MODE_CLOCK_HIGH; - if (intel_sdvo->is_lvds == true) { - if (intel_sdvo->sdvo_lvds_fixed_mode == NULL) - return MODE_PANEL; - + if (intel_sdvo->is_lvds) { if (mode->hdisplay > intel_sdvo->sdvo_lvds_fixed_mode->hdisplay) return MODE_PANEL; @@ -1534,7 +1531,7 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect intel_sdvo->base.needs_tv_clock = true; } if (response & SDVO_LVDS_MASK) - intel_sdvo->is_lvds = true; + intel_sdvo->is_lvds = intel_sdvo->sdvo_lvds_fixed_mode != NULL; } return ret; @@ -1697,6 +1694,7 @@ end: if (newmode->type & DRM_MODE_TYPE_PREFERRED) { intel_sdvo->sdvo_lvds_fixed_mode = drm_mode_duplicate(connector->dev, newmode); + intel_sdvo->is_lvds = true; break; } } @@ -2190,8 +2188,6 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) encoder->encoder_type = DRM_MODE_ENCODER_LVDS; connector->connector_type = DRM_MODE_CONNECTOR_LVDS; - intel_sdvo->is_lvds = true; - if (device == 0) { intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS0; intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0; -- cgit v0.10.2 From ce17178094f368d9e3f39b2cb4303da5ed633dd4 Mon Sep 17 00:00:00 2001 From: Zou Nan hai Date: Fri, 25 Jun 2010 13:40:22 +0800 Subject: drm/i915: Enable RC6 on Ironlake. RC6 allows the GPU to enter a lower power state when the GPU is idle. Signed-off-by: Zou Nan hai [anholt: Fixed the !renderctx error path to actually not enable RC6.] Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4668e9b..149c18b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5753,7 +5753,8 @@ void intel_init_clock_gating(struct drm_device *dev) ILK_DPFC_DIS2 | ILK_CLK_FBC); } - return; + if (IS_GEN6(dev)) + return; } else if (IS_G4X(dev)) { uint32_t dspclk_gate; I915_WRITE(RENCLK_GATE_D1, 0); @@ -5814,9 +5815,11 @@ void intel_init_clock_gating(struct drm_device *dev) OUT_RING(MI_FLUSH); ADVANCE_LP_RING(); } - } else + } else { DRM_DEBUG_KMS("Failed to allocate render context." - "Disable RC6\n"); + "Disable RC6\n"); + return; + } } if (I915_HAS_RC6(dev) && drm_core_check_feature(dev, DRIVER_MODESET)) { -- cgit v0.10.2 From 669502ff31d7dba1849aec7ee2450a3c61f57d39 Mon Sep 17 00:00:00 2001 From: Andy Chittenden Date: Tue, 10 Aug 2010 10:19:53 -0400 Subject: SUNRPC: fix NFS client over TCP hangs due to packet loss (Bug 16494) When reusing a TCP connection, ensure that it's aborted if a previous shutdown attempt has been made on that connection so that the RPC over TCP recovery mechanism succeeds. Signed-off-by: Andy Chittenden Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 7ca65c7..66d1369 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1305,10 +1305,11 @@ static void xs_tcp_state_change(struct sock *sk) if (!(xprt = xprt_from_sock(sk))) goto out; dprintk("RPC: xs_tcp_state_change client %p...\n", xprt); - dprintk("RPC: state %x conn %d dead %d zapped %d\n", + dprintk("RPC: state %x conn %d dead %d zapped %d sk_shutdown %d\n", sk->sk_state, xprt_connected(xprt), sock_flag(sk, SOCK_DEAD), - sock_flag(sk, SOCK_ZAPPED)); + sock_flag(sk, SOCK_ZAPPED), + sk->sk_shutdown); switch (sk->sk_state) { case TCP_ESTABLISHED: @@ -1779,10 +1780,25 @@ static void xs_tcp_reuse_connection(struct rpc_xprt *xprt, struct sock_xprt *tra { unsigned int state = transport->inet->sk_state; - if (state == TCP_CLOSE && transport->sock->state == SS_UNCONNECTED) - return; - if ((1 << state) & (TCPF_ESTABLISHED|TCPF_SYN_SENT)) - return; + if (state == TCP_CLOSE && transport->sock->state == SS_UNCONNECTED) { + /* we don't need to abort the connection if the socket + * hasn't undergone a shutdown + */ + if (transport->inet->sk_shutdown == 0) + return; + dprintk("RPC: %s: TCP_CLOSEd and sk_shutdown set to %d\n", + __func__, transport->inet->sk_shutdown); + } + if ((1 << state) & (TCPF_ESTABLISHED|TCPF_SYN_SENT)) { + /* we don't need to abort the connection if the socket + * hasn't undergone a shutdown + */ + if (transport->inet->sk_shutdown == 0) + return; + dprintk("RPC: %s: ESTABLISHED/SYN_SENT " + "sk_shutdown set to %d\n", + __func__, transport->inet->sk_shutdown); + } xs_abort_connection(xprt, transport); } -- cgit v0.10.2 From f5a73672d1811f2fb1dcb62ca90ceb12b2050ae7 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Tue, 10 Aug 2010 10:20:05 -0400 Subject: NFS: allow close-to-open cache semantics to apply to root of NFS filesystem To obey NFS cache semantics, the client must verify the cached attributes when a file is opened. In most cases this is done by a call to d_validate as one of the last steps in path_walk. However for the root of a filesystem, d_validate is only ever called on the mounted-on filesystem (except when the path ends '.' or '..'). So NFS has no chance to validate the attributes. So, in nfs_opendir, we revalidate the attributes if the opened directory is the mountpoint. This may cause double-validation for "." and ".." lookups, but that is better than missing regular /path/name lookups completely. Signed-off-by: NeilBrown Signed-off-by: Trond Myklebust diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 29539ce..bd91b27 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -140,6 +140,13 @@ nfs_opendir(struct inode *inode, struct file *filp) /* Call generic open code in order to cache credentials */ res = nfs_open(inode, filp); + if (filp->f_path.dentry == filp->f_path.mnt->mnt_root) { + /* This is a mountpoint, so d_revalidate will never + * have been called, so we need to refresh the + * inode (for close-open consistency) ourselves. + */ + __nfs_revalidate_inode(NFS_SERVER(inode), inode); + } return res; } -- cgit v0.10.2 From 9b00c64318cc337846a7a08a5678f5f19aeff188 Mon Sep 17 00:00:00 2001 From: "Patrick J. LoPresti" Date: Tue, 10 Aug 2010 17:28:01 -0400 Subject: nfs: Add "lookupcache" to displayed mount options Running "cat /proc/mounts" fails to display the "lookupcache" option. This oversight cost me a bunch of wasted time recently. The following simple patch fixes it. CC: stable Signed-off-by: Patrick LoPresti Signed-off-by: Trond Myklebust diff --git a/fs/nfs/super.c b/fs/nfs/super.c index f1ae39f..3d0d63c 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -655,6 +655,13 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, if (nfss->options & NFS_OPTION_FSCACHE) seq_printf(m, ",fsc"); + + if (nfss->flags & NFS_MOUNT_LOOKUP_CACHE_NONEG) { + if (nfss->flags & NFS_MOUNT_LOOKUP_CACHE_NONE) + seq_printf(m, ",lookupcache=none"); + else + seq_printf(m, ",lookupcache=pos"); + } } /* -- cgit v0.10.2 From 5d7ca35a182a626f8ed5596023ad42eb219a332e Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Wed, 11 Aug 2010 12:42:15 -0400 Subject: nfs: Remove redundant NULL check upon kfree() Signed-off-by: Davidlohr Bueso Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 7ffbb98..6b44bbf 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2273,8 +2273,7 @@ static int nfs4_get_referral(struct inode *dir, const struct qstr *name, struct out: if (page) __free_page(page); - if (locations) - kfree(locations); + kfree(locations); return status; } -- cgit v0.10.2 From 7a8b80eb38b248cfdf84048dad12073d5cfba3e6 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 11 Aug 2010 12:47:08 -0400 Subject: xprtrdma: Do not truncate iova_start values in frmr registrations. A bad cast causes the iova_start, which in this case is a 64b DMA bus address, to be truncated on 32b systems. This breaks frmrs on 32b systems. No cast is needed. Signed-off-by: Steve Wise Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 27015c6..3bdbd9f 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -1490,7 +1490,7 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg, memset(&frmr_wr, 0, sizeof frmr_wr); frmr_wr.opcode = IB_WR_FAST_REG_MR; frmr_wr.send_flags = 0; /* unsignaled */ - frmr_wr.wr.fast_reg.iova_start = (unsigned long)seg1->mr_dma; + frmr_wr.wr.fast_reg.iova_start = seg1->mr_dma; frmr_wr.wr.fast_reg.page_list = seg1->mr_chunk.rl_mw->r.frmr.fr_pgl; frmr_wr.wr.fast_reg.page_list_len = i; frmr_wr.wr.fast_reg.page_shift = PAGE_SHIFT; -- cgit v0.10.2 From 15cdc644b268a9a9ce73ce0b153129222c254b7b Mon Sep 17 00:00:00 2001 From: Tom Tucker Date: Wed, 11 Aug 2010 12:47:24 -0400 Subject: rpcrdma: Fix SQ size calculation when memreg is FRMR This patch updates the computation to include the worst case situation where three FRMR are required to map a single RPC REQ. Signed-off-by: Tom Tucker Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c index e5e28d1..2ac3f6e 100644 --- a/net/sunrpc/xprtrdma/rpc_rdma.c +++ b/net/sunrpc/xprtrdma/rpc_rdma.c @@ -249,6 +249,8 @@ rpcrdma_create_chunks(struct rpc_rqst *rqst, struct xdr_buf *target, req->rl_nchunks = nchunks; BUG_ON(nchunks == 0); + BUG_ON((r_xprt->rx_ia.ri_memreg_strategy == RPCRDMA_FRMR) + && (nchunks > 3)); /* * finish off header. If write, marshal discrim and nchunks. diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 3bdbd9f..5f4c7b3 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -650,10 +650,22 @@ rpcrdma_ep_create(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia, ep->rep_attr.cap.max_send_wr = cdata->max_requests; switch (ia->ri_memreg_strategy) { case RPCRDMA_FRMR: - /* Add room for frmr register and invalidate WRs */ - ep->rep_attr.cap.max_send_wr *= 3; - if (ep->rep_attr.cap.max_send_wr > devattr.max_qp_wr) - return -EINVAL; + /* Add room for frmr register and invalidate WRs. + * 1. FRMR reg WR for head + * 2. FRMR invalidate WR for head + * 3. FRMR reg WR for pagelist + * 4. FRMR invalidate WR for pagelist + * 5. FRMR reg WR for tail + * 6. FRMR invalidate WR for tail + * 7. The RDMA_SEND WR + */ + ep->rep_attr.cap.max_send_wr *= 7; + if (ep->rep_attr.cap.max_send_wr > devattr.max_qp_wr) { + cdata->max_requests = devattr.max_qp_wr / 7; + if (!cdata->max_requests) + return -EINVAL; + ep->rep_attr.cap.max_send_wr = cdata->max_requests * 7; + } break; case RPCRDMA_MEMWINDOWS_ASYNC: case RPCRDMA_MEMWINDOWS: -- cgit v0.10.2 From 0702099bd86c33c2dcdbd3963433a61f3f503901 Mon Sep 17 00:00:00 2001 From: "J. R. Okajima" Date: Wed, 11 Aug 2010 13:10:16 -0400 Subject: NFS: fix the return value of nfs_file_fsync() By the commit af7fa16 2010-08-03 NFS: Fix up the fsync code close(2) became returning the non-zero value even if it went well. nfs_file_fsync() should return 0 when "status" is positive. Signed-off-by: J. R. Okajima Signed-off-by: Trond Myklebust diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 2d141a7..eb51bd6 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -323,7 +323,7 @@ nfs_file_fsync(struct file *file, int datasync) have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); if (have_error) ret = xchg(&ctx->error, 0); - if (!ret) + if (!ret && status < 0) ret = status; return ret; } -- cgit v0.10.2 From 2f81b47135a971a22ccad9f3cc8c68a583b93ea4 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 11 Aug 2010 16:11:00 -0400 Subject: ipw2100: register pm_qos request before registering pci driver It is necessary to call pm_qos_add_request prior to calling pm_qos_update_request. It was revealed that ipw2100 has been doing this wrong since "pm_qos: Get rid of the allocation in pm_qos_add_request()" (commit 82f682514a5df89ffb3890627eebf0897b7a84ec) added a WARN that results in the following backtrace: WARNING: at kernel/pm_qos_params.c:264 pm_qos_update_request+0x5e/0x70() pm_qos_update_request() called for unknown object Call Trace: [] ? warn_slowpath_common+0x78/0xb0 [] ? pm_qos_update_request+0x5e/0x70 [] ? pm_qos_update_request+0x5e/0x70 [] ? warn_slowpath_fmt+0x33/0x40 [] ? pm_qos_update_request+0x5e/0x70 [] ? ipw2100_up+0x3f/0xf10 [ipw2100] [] ? vsnprintf+0xc9/0x530 [] ? ipw2100_net_init+0x2c/0x1c0 [ipw2100] [] ? register_netdevice+0x7d/0x3c0 [] ? ipw2100_irq_tasklet+0x910/0x9a0 [ipw2100] [] ? register_netdev+0x2f/0x40 [] ? ipw2100_pci_init_one+0xd21/0x1060 [ipw2100] [] ? local_pci_probe+0xb/0x10 [] ? pci_device_probe+0x69/0x90 [] ? driver_probe_device+0x74/0x180 [] ? sysfs_create_dir+0x6a/0xb0 [] ? __driver_attach+0x79/0x80 [] ? __driver_attach+0x0/0x80 [] ? bus_for_each_dev+0x52/0x80 [] ? driver_attach+0x16/0x20 [] ? __driver_attach+0x0/0x80 [] ? bus_add_driver+0x17f/0x250 [] ? pci_device_shutdown+0x0/0x20 [] ? pci_device_remove+0x0/0x40 [] ? driver_register+0x63/0x120 [] ? __pci_register_driver+0x36/0xa0 [] ? ipw2100_init+0x48/0x67 [ipw2100] [] ? do_one_initcall+0x32/0x170 [] ? __vunmap+0xb8/0xf0 [] ? ipw2100_init+0x0/0x67 [ipw2100] [] ? sys_init_module+0x161/0x1000 [] ? sys_close+0x67/0xe0 [] ? syscall_call+0x7/0xb This patch moves pm_qos_add_request prior to pci_register_driver in ipw2100 in order to avoid this problem. Reported-by: Christoph Fritz Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 16bbfa3..1189dbb 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -6665,12 +6665,13 @@ static int __init ipw2100_init(void) printk(KERN_INFO DRV_NAME ": %s, %s\n", DRV_DESCRIPTION, DRV_VERSION); printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT); + pm_qos_add_request(&ipw2100_pm_qos_req, PM_QOS_CPU_DMA_LATENCY, + PM_QOS_DEFAULT_VALUE); + ret = pci_register_driver(&ipw2100_pci_driver); if (ret) goto out; - pm_qos_add_request(&ipw2100_pm_qos_req, PM_QOS_CPU_DMA_LATENCY, - PM_QOS_DEFAULT_VALUE); #ifdef CONFIG_IPW2100_DEBUG ipw2100_debug_level = debug; ret = driver_create_file(&ipw2100_pci_driver.driver, -- cgit v0.10.2 From da93f10684bfba2983a70c10b5d417232b6a5245 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 11 Aug 2010 20:27:43 +0530 Subject: ath9k_htc: fix panic on packet injection using airbase-ng tool. This should fix the oops which occurs during the packet injection on monitor interface. EIP is at ath9k_htc_tx_start+0x69/0x220 [ath9k_htc] [] ? invoke_tx_handlers+0xa5a/0xee0 [mac80211] [] ? ath9k_htc_tx+0x44/0xe0 [ath9k_htc] [] ? __ieee80211_tx+0xf8/0x190 [mac80211] [] ? ieee80211_tx+0x9d/0x1a0 [mac80211] [] ? ieee80211_xmit+0x9c/0x1c0 [mac80211] [] ? ieee80211_monitor_start_xmit+0x85/0xb0 [mac80211] [] ? dev_hard_start_xmit+0x1ad/0x210 [] ? __alloc_skb+0x52/0x130 [] ? sch_direct_xmit+0x105/0x170 [] ? dev_queue_xmit+0x37f/0x4b0 [] ? packet_snd+0x21e/0x250 [] ? packet_sendmsg+0x32/0x40 [] ? sock_aio_write+0x113/0x130 [] ? do_sync_write+0xc4/0x100 [] ? autoremove_wake_function+0x0/0x50 [] ? security_file_permission+0x14/0x20 [] ? rw_verify_area+0x64/0xe0 [] ? handle_mm_fault+0x338/0x390 [] ? vfs_write+0x185/0x1a0 [] ? do_page_fault+0x160/0x3a0 [] ? sys_write+0x42/0x70 [] ? syscall_call+0x7/0xb Signed-off-by: Rajkumar Manoharan Cc: stable@kernel.org Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index bd0b4ac..2a6e45a 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -78,18 +78,23 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_sta *sta = tx_info->control.sta; struct ath9k_htc_sta *ista; - struct ath9k_htc_vif *avp; struct ath9k_htc_tx_ctl tx_ctl; enum htc_endpoint_id epid; u16 qnum; __le16 fc; u8 *tx_fhdr; - u8 sta_idx; + u8 sta_idx, vif_idx; hdr = (struct ieee80211_hdr *) skb->data; fc = hdr->frame_control; - avp = (struct ath9k_htc_vif *) tx_info->control.vif->drv_priv; + if (tx_info->control.vif && + (struct ath9k_htc_vif *) tx_info->control.vif->drv_priv) + vif_idx = ((struct ath9k_htc_vif *) + tx_info->control.vif->drv_priv)->index; + else + vif_idx = priv->nvifs; + if (sta) { ista = (struct ath9k_htc_sta *) sta->drv_priv; sta_idx = ista->index; @@ -106,7 +111,7 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr)); tx_hdr.node_idx = sta_idx; - tx_hdr.vif_idx = avp->index; + tx_hdr.vif_idx = vif_idx; if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { tx_ctl.type = ATH9K_HTC_AMPDU; @@ -169,7 +174,7 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) tx_ctl.type = ATH9K_HTC_NORMAL; mgmt_hdr.node_idx = sta_idx; - mgmt_hdr.vif_idx = avp->index; + mgmt_hdr.vif_idx = vif_idx; mgmt_hdr.tidno = 0; mgmt_hdr.flags = 0; -- cgit v0.10.2 From 7032269e87ade34cc12891675371fa2ac150a620 Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Thu, 12 Aug 2010 19:07:40 -0400 Subject: HID: hiddev: protect against disconnect/NULL-dereference race One of our users reports consistently hitting a NULL dereference that resolves to the "hid_to_usb_dev(hid);" call in hiddev_ioctl(), when disconnecting a Lego WeDo USB HID device from an OLPC XO running Scratch software. There's a FIXME comment and a guard against the dereference, but that happens farther down the function than the initial dereference does. This patch moves the call to be below the guard, and the user reports that it fixes the problem for him. OLPC bug report: http://dev.laptop.org/ticket/10174 Signed-off-by: Chris Ball Signed-off-by: Jiri Kosina diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 254a003..f285017 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -587,7 +587,7 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct hiddev_list *list = file->private_data; struct hiddev *hiddev = list->hiddev; struct hid_device *hid = hiddev->hid; - struct usb_device *dev = hid_to_usb_dev(hid); + struct usb_device *dev; struct hiddev_collection_info cinfo; struct hiddev_report_info rinfo; struct hiddev_field_info finfo; @@ -601,9 +601,11 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) /* Called without BKL by compat methods so no BKL taken */ /* FIXME: Who or what stop this racing with a disconnect ?? */ - if (!hiddev->exist) + if (!hiddev->exist || !hid) return -EIO; + dev = hid_to_usb_dev(hid); + switch (cmd) { case HIDIOCGVERSION: -- cgit v0.10.2 From 9c9e54a8df0be48aa359744f412377cc55c3b7d2 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 13 Aug 2010 12:19:45 +0200 Subject: HID: hiddev: fix memory corruption due to invalid intfdata Commit bd25f4dd6972755579d0 ("HID: hiddev: use usb_find_interface, get rid of BKL") introduced using of private intfdata in hiddev for purpose of storing hiddev pointer. This is a problem, because intf pointer is already being set to struct hid_device pointer by HID core. This obviously lead to memory corruptions at device disconnect time, such as WARNING: at lib/kobject.c:595 kobject_put+0x37/0x4b() kobject: '(null)' (ffff88011e9cd898): is not initialized, yet kobject_put() is being called. Convert hiddev into accessing hiddev through struct hid_device which is in intfdata already. Reported-and-tested-by: Markus Trippelsdorf Reported-and-tested-by: Heinz Diehl Reported-and-tested-by: Alan Ott Signed-off-by: Jiri Kosina diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index f285017..0a29c51 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -266,13 +266,15 @@ static int hiddev_open(struct inode *inode, struct file *file) { struct hiddev_list *list; struct usb_interface *intf; + struct hid_device *hid; struct hiddev *hiddev; int res; intf = usb_find_interface(&hiddev_driver, iminor(inode)); if (!intf) return -ENODEV; - hiddev = usb_get_intfdata(intf); + hid = usb_get_intfdata(intf); + hiddev = hid->hiddev; if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL))) return -ENOMEM; @@ -890,7 +892,6 @@ int hiddev_connect(struct hid_device *hid, unsigned int force) hid->hiddev = hiddev; hiddev->hid = hid; hiddev->exist = 1; - usb_set_intfdata(usbhid->intf, usbhid); retval = usb_register_dev(usbhid->intf, &hiddev_class); if (retval) { err_hid("Not able to get a minor for this device."); -- cgit v0.10.2 From 71ba186c123630ddab17667ec9ecf7e2ef211295 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Thu, 12 Aug 2010 14:23:28 +0530 Subject: ath9k_htc: Fix disconnect issue in HT40 mode. Some APs advertise that they may be HT40 capable in the capabilites but the current operating channel configuration may be only HT20. This causes disconnection as ath9k_htc sets WLAN_RC_40_FLAG despite the AP operating in HT20 mode. Hence set this flag only if the current channel configuration is HT40 enabled. Cc: stable@kernel.org Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index ebed9d1..7d09b4b 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -366,7 +366,8 @@ static void ath9k_htc_setup_rate(struct ath9k_htc_priv *priv, caps = WLAN_RC_HT_FLAG; if (sta->ht_cap.mcs.rx_mask[1]) caps |= WLAN_RC_DS_FLAG; - if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) + if ((sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) && + (conf_is_ht40(&priv->hw->conf))) caps |= WLAN_RC_40_FLAG; if (conf_is_ht40(&priv->hw->conf) && (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)) -- cgit v0.10.2 From fe0dbcc9d2e941328b3269dab102b94ad697ade5 Mon Sep 17 00:00:00 2001 From: Yuri Kululin Date: Fri, 13 Aug 2010 13:46:12 +0400 Subject: wl1251: fix trigger scan timeout usage Use appropriate command (CMD_TRIGGER_SCAN_TO) instead of scan command (CMD_SCAN) to configure trigger scan timeout. This was broken in commit 3a98c30f3e8bb1f32b5bcb74a39647b3670de275. This fix address the bug reported here: https://bugzilla.kernel.org/show_bug.cgi?id=16554 Cc: stable@kernel.org Signed-off-by: Yuri Ershov Signed-off-by: Yuri Kululin Acked-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index a37b30c..ce3722f 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -484,7 +484,7 @@ int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout) cmd->timeout = timeout; - ret = wl1251_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd)); + ret = wl1251_cmd_send(wl, CMD_TRIGGER_SCAN_TO, cmd, sizeof(*cmd)); if (ret < 0) { wl1251_error("cmd trigger scan to failed: %d", ret); goto out; -- cgit v0.10.2 From ca6cff1f80f30cc6313a943339361ad6f9e76548 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Fri, 13 Aug 2010 18:36:40 +0530 Subject: ath9k_htc: load proper firmware for device ID 7015 This patch handles the firmware loading properly for device ID 7015. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index 8750c55..7f48df1 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -191,6 +191,7 @@ #define AR9287_EEP_NO_BACK_VER AR9287_EEP_MINOR_VER_1 #define AR9287_EEP_START_LOC 128 +#define AR9287_HTC_EEP_START_LOC 256 #define AR9287_NUM_2G_CAL_PIERS 3 #define AR9287_NUM_2G_CCK_TARGET_POWERS 3 #define AR9287_NUM_2G_20_TARGET_POWERS 3 diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index 4a52cf0..dff2da7 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -34,9 +34,14 @@ static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah) struct ar9287_eeprom *eep = &ah->eeprom.map9287; struct ath_common *common = ath9k_hw_common(ah); u16 *eep_data; - int addr, eep_start_loc = AR9287_EEP_START_LOC; + int addr, eep_start_loc; eep_data = (u16 *)eep; + if (ah->hw_version.devid == 0x7015) + eep_start_loc = AR9287_HTC_EEP_START_LOC; + else + eep_start_loc = AR9287_EEP_START_LOC; + if (!ath9k_hw_use_flash(ah)) { ath_print(common, ATH_DBG_EEPROM, "Reading from EEPROM, not flash\n"); diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 61c1bee..17e7a9a 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -799,7 +799,7 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev) } kfree(buf); - if (hif_dev->device_id == 0x7010) + if ((hif_dev->device_id == 0x7010) || (hif_dev->device_id == 0x7015)) firm_offset = AR7010_FIRMWARE_TEXT; else firm_offset = AR9271_FIRMWARE_TEXT; @@ -901,6 +901,7 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface, switch(hif_dev->device_id) { case 0x7010: + case 0x7015: case 0x9018: if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x0202) hif_dev->fw_name = FIRMWARE_AR7010_1_1; @@ -912,11 +913,6 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface, break; } - if (!hif_dev->fw_name) { - dev_err(&udev->dev, "Can't determine firmware !\n"); - goto err_htc_hw_alloc; - } - ret = ath9k_hif_usb_dev_init(hif_dev); if (ret) { ret = -EINVAL; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 148b433..2d42791 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -245,6 +245,7 @@ static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid) switch(devid) { case 0x7010: + case 0x7015: case 0x9018: priv->htc->credits = 45; break; diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 633e3d9..d01c4ad 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -899,6 +899,7 @@ #define AR_DEVID_7010(_ah) \ (((_ah)->hw_version.devid == 0x7010) || \ + ((_ah)->hw_version.devid == 0x7015) || \ ((_ah)->hw_version.devid == 0x9018)) #define AR_RADIO_SREV_MAJOR 0xf0 -- cgit v0.10.2 From 6ccf15a1a76d2ff915cdef6ae4d12d0170087118 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Fri, 13 Aug 2010 11:27:28 -0400 Subject: ath5k: disable ASPM L0s for all cards Atheros PCIe wireless cards handled by ath5k do require L0s disabled. For distributions shipping with CONFIG_PCIEASPM (this will be enabled by default in the future in 2.6.36) this will also mean both L1 and L0s will be disabled when a pre 1.1 PCIe device is detected. We do know L1 works correctly even for all ath5k pre 1.1 PCIe devices though but cannot currently undue the effect of a blacklist, for details you can read pcie_aspm_sanity_check() and see how it adjusts the device link capability. It may be possible in the future to implement some PCI API to allow drivers to override blacklists for pre 1.1 PCIe but for now it is best to accept that both L0s and L1 will be disabled completely for distributions shipping with CONFIG_PCIEASPM rather than having this issue present. Motivation for adding this new API will be to help with power consumption for some of these devices. Example of issues you'd see: - On the Acer Aspire One (AOA150, Atheros Communications Inc. AR5001 Wireless Network Adapter [168c:001c] (rev 01)) doesn't work well with ASPM enabled, the card will eventually stall on heavy traffic with often 'unsupported jumbo' warnings appearing. Disabling ASPM L0s in ath5k fixes these problems. - On the same card you would see a storm of RXORN interrupts even though medium is idle. Credit for root causing and fixing the bug goes to Jussi Kivilinna. Cc: David Quan Cc: Matthew Garrett Cc: Tim Gardner Cc: Jussi Kivilinna Cc: stable@kernel.org Signed-off-by: Luis R. Rodriguez Signed-off-by: Maxim Levitsky Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 0d5de25..373dcfe 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -476,6 +477,26 @@ ath5k_pci_probe(struct pci_dev *pdev, int ret; u8 csz; + /* + * L0s needs to be disabled on all ath5k cards. + * + * For distributions shipping with CONFIG_PCIEASPM (this will be enabled + * by default in the future in 2.6.36) this will also mean both L1 and + * L0s will be disabled when a pre 1.1 PCIe device is detected. We do + * know L1 works correctly even for all ath5k pre 1.1 PCIe devices + * though but cannot currently undue the effect of a blacklist, for + * details you can read pcie_aspm_sanity_check() and see how it adjusts + * the device link capability. + * + * It may be possible in the future to implement some PCI API to allow + * drivers to override blacklists for pre 1.1 PCIe but for now it is + * best to accept that both L0s and L1 will be disabled completely for + * distributions shipping with CONFIG_PCIEASPM rather than having this + * issue present. Motivation for adding this new API will be to help + * with power consumption for some of these devices. + */ + pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S); + ret = pci_enable_device(pdev); if (ret) { dev_err(&pdev->dev, "can't enable device\n"); -- cgit v0.10.2 From 2f174847b0fdd4eb9f482030a284db24aef7a97f Mon Sep 17 00:00:00 2001 From: eric miao Date: Thu, 12 Aug 2010 16:43:00 +0100 Subject: ARM: 6326/1: kgdb: fix GDB_MAX_REGS no longer used According to commit 22eeef4bb2a7fd225089c0044060ed1fbf091958 kgdb,arm: Individual register get/set for arm It's now replaced by DBG_MAX_REG_NUM. Cc: Jason Wessel Signed-off-by: Eric Miao Signed-off-by: Russell King diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c index 778c2f7..d6e8b4d 100644 --- a/arch/arm/kernel/kgdb.c +++ b/arch/arm/kernel/kgdb.c @@ -79,7 +79,7 @@ sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task) return; /* Initialize to zero */ - for (regno = 0; regno < GDB_MAX_REGS; regno++) + for (regno = 0; regno < DBG_MAX_REG_NUM; regno++) gdb_regs[regno] = 0; /* Otherwise, we have only some registers from switch_to() */ -- cgit v0.10.2 From ce60659ad838a77d71aa817a6781659799970ae1 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Jul 2010 13:19:39 -0700 Subject: iwlwifi: long monitor timer Change the name for monitor timer, also adding define for long monitor timer; long monitor timer can be used for the type of devices require longer time to determine the uCode is stuck on tx and needed reload. Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index fec0262..0b779a4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -265,7 +265,7 @@ struct iwl_cfg iwl1000_bgn_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 128, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -297,7 +297,7 @@ struct iwl_cfg iwl1000_bg_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 128, .ucode_tracing = true, .sensitivity_calib_by_driver = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 6950a78..8ccfcd0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2731,7 +2731,7 @@ static struct iwl_cfg iwl3945_bg_cfg = { .led_compensation = 64, .broken_powersave = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .tx_power_by_driver = true, }; @@ -2752,7 +2752,7 @@ static struct iwl_cfg iwl3945_abg_cfg = { .led_compensation = 64, .broken_powersave = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .tx_power_by_driver = true, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index d6da356..d92b729 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2322,7 +2322,7 @@ struct iwl_cfg iwl4965_agn_cfg = { .led_compensation = 61, .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .temperature_kelvin = true, .max_event_log_size = 512, .tx_power_by_driver = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index aacf377..cd9f9fc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -510,7 +510,7 @@ struct iwl_cfg iwl5300_agn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -541,7 +541,7 @@ struct iwl_cfg iwl5100_bgn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -570,7 +570,7 @@ struct iwl_cfg iwl5100_abg_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -601,7 +601,7 @@ struct iwl_cfg iwl5100_agn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -632,7 +632,7 @@ struct iwl_cfg iwl5350_agn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -663,7 +663,7 @@ struct iwl_cfg iwl5150_agn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -693,7 +693,7 @@ struct iwl_cfg iwl5150_abg_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index af4fd50..b6468e9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -388,7 +388,7 @@ struct iwl_cfg iwl6000g2a_2agn_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -424,7 +424,7 @@ struct iwl_cfg iwl6000g2a_2abg_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, @@ -459,7 +459,7 @@ struct iwl_cfg iwl6000g2a_2bg_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, @@ -496,7 +496,7 @@ struct iwl_cfg iwl6000g2b_2agn_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, @@ -532,7 +532,7 @@ struct iwl_cfg iwl6000g2b_2abg_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, @@ -570,7 +570,7 @@ struct iwl_cfg iwl6000g2b_2bgn_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, @@ -606,7 +606,7 @@ struct iwl_cfg iwl6000g2b_2bg_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, @@ -644,7 +644,7 @@ struct iwl_cfg iwl6000g2b_bgn_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, @@ -680,7 +680,7 @@ struct iwl_cfg iwl6000g2b_bg_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, @@ -721,7 +721,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 1024, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -756,7 +756,7 @@ struct iwl_cfg iwl6000i_2abg_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 1024, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -791,7 +791,7 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 1024, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -828,7 +828,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1500, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 1024, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -866,7 +866,7 @@ struct iwl_cfg iwl6050g2_bgn_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1500, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 1024, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -902,7 +902,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1500, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 1024, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -940,7 +940,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 1024, .ucode_tracing = true, .sensitivity_calib_by_driver = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index f35bcad..2e97cd2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1049,7 +1049,8 @@ struct iwl_event_log { #define IWL_DELAY_NEXT_FORCE_FW_RELOAD (HZ*5) /* timer constants use to monitor and recover stuck tx queues in mSecs */ -#define IWL_MONITORING_PERIOD (1000) +#define IWL_DEF_MONITORING_PERIOD (1000) +#define IWL_LONG_MONITORING_PERIOD (5000) #define IWL_ONE_HUNDRED_MSECS (100) #define IWL_SIXTY_SECS (60000) -- cgit v0.10.2 From 3198c68cb4e1967f59244f0a0b9f46102d617373 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Jul 2010 13:19:40 -0700 Subject: iwlwifi: use long monitor timer to avoid un-necessary reload For 5000 and 6000g2b series of devices, use long monitor timer to check stuck tx queues. .6000g2b series device, it is WiFi/BT combo device, there are some cases, tx queues are not move for a period of time because the WiFi/BT coex. .5000 series device, it is being reported firmware got reload more often than necessary, so extend the timer to avoid un-necessary reload. Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index cd9f9fc..0cbefa3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -510,7 +510,7 @@ struct iwl_cfg iwl5300_agn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -541,7 +541,7 @@ struct iwl_cfg iwl5100_bgn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -570,7 +570,7 @@ struct iwl_cfg iwl5100_abg_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -601,7 +601,7 @@ struct iwl_cfg iwl5100_agn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -632,7 +632,7 @@ struct iwl_cfg iwl5350_agn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index b6468e9..cee06b9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -496,7 +496,7 @@ struct iwl_cfg iwl6000g2b_2agn_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, @@ -532,7 +532,7 @@ struct iwl_cfg iwl6000g2b_2abg_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, @@ -570,7 +570,7 @@ struct iwl_cfg iwl6000g2b_2bgn_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, @@ -606,7 +606,7 @@ struct iwl_cfg iwl6000g2b_2bg_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, @@ -644,7 +644,7 @@ struct iwl_cfg iwl6000g2b_bgn_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, @@ -680,7 +680,7 @@ struct iwl_cfg iwl6000g2b_bg_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, -- cgit v0.10.2 From 84062dd3a6a045395a43de1d9adc9b8eb2d1426e Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 14 Aug 2010 23:22:16 +0200 Subject: kconfig: fix savedefconfig with choice marked optional savedefconfig failed to save the correct minimal config when it encountered a choice marked optional. Consider following minimal configuration: $cat Kconfig choice prompt "choice" optional config A bool "a" config B bool "b" endchoice $cat .config | grep -v ^# CONFIG_A=y $conf --savedefconfig=defconfig Kconfig would before this fix result in an empty file, because kconfig would assume that CONFIG_A=y is a default value. But because the choice is optional the default is that both A and B are =n. Fix so we handle optional choices correct. Signed-off-by: Sam Ravnborg Signed-off-by: Michal Marek diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index c39327e..515253f 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -497,7 +497,9 @@ int conf_write_defconfig(const char *filename) /* * If symbol is a choice value and equals to the * default for a choice - skip. - * But only if value is bool and equal to "y" . + * But only if value is bool and equal to "y" and + * choice is not "optional". + * (If choice is "optional" then all values can be "n") */ if (sym_is_choice_value(sym)) { struct symbol *cs; @@ -505,7 +507,7 @@ int conf_write_defconfig(const char *filename) cs = prop_get_symbol(sym_get_choice_prop(sym)); ds = sym_choice_default(cs); - if (sym == ds) { + if (!sym_is_optional(cs) && sym == ds) { if ((sym->type == S_BOOLEAN) && sym_get_tristate_value(sym) == yes) goto next_menu; -- cgit v0.10.2 From 3643f849d7da5c12da589beb03c12303fe79b841 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 14 Aug 2010 14:40:00 +0200 Subject: kconfig: fix segfault when detecting recursive dependency Following sample Kconfig generated a segfault: config FOO bool select PERF_EVENTS if HAVE_HW_BREAKPOINT config PERF_EVENTS bool config HAVE_HW_BREAKPOINT bool depends on PERF_EVENTS Fix by reverting back to a valid property if there was no property on the stack of symbols. The above pattern were seen in sh Kconfig. A fix for the Kconfig file has been sent to the sh folks. Signed-off-by: Sam Ravnborg Signed-off-by: Michal Marek diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index e95718f..943712c 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -937,6 +937,8 @@ static void sym_check_print_recursive(struct symbol *last_sym) sym = stack->sym; next_sym = stack->next ? stack->next->sym : last_sym; prop = stack->prop; + if (prop == NULL) + prop = stack->sym->prop; /* for choice values find the menu entry (used below) */ if (sym_is_choice(sym) || sym_is_choice_value(sym)) { -- cgit v0.10.2 From bd365591dfb942d1447b8043e21e8ff112630db4 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Sat, 14 Aug 2010 23:56:21 +0100 Subject: ARM: 6328/1: Build with -fno-dwarf2-cfi-asm Commit d0679c7 restricted this workaround to powerpc only, but it turns out that ARM needs it as well. Fixes https://bugzilla.kernel.org/show_bug.cgi?id=16310 . Reported-and-Tested-by: Robert Nelson Acked-by: Mikael Pettersson Signed-off-by: Michal Marek Signed-off-by: Russell King diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 99b8200..59c1ce8 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -21,6 +21,9 @@ GZFLAGS :=-9 # Explicitly specifiy 32-bit ARM ISA since toolchain default can be -mthumb: KBUILD_CFLAGS +=$(call cc-option,-marm,) +# Never generate .eh_frame +KBUILD_CFLAGS += $(call cc-option,-fno-dwarf2-cfi-asm) + # Do not use arch/arm/defconfig - it's always outdated. # Select a platform tht is kept up-to-date KBUILD_DEFCONFIG := versatile_defconfig -- cgit v0.10.2 From 2f09a4d5daaa36690d506fafda9c24f2be866f6b Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 14 Aug 2010 22:38:09 -0700 Subject: xfrm: Use GFP_ATOMIC in xfrm_compile_policy As xfrm_compile_policy runs within a read_lock, we cannot use GFP_KERNEL for memory allocations. Reported-by: Luca Tettamanti Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index ba59983..b14ed4b 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -2504,7 +2504,7 @@ static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt, if (p->dir > XFRM_POLICY_OUT) return NULL; - xp = xfrm_policy_alloc(net, GFP_KERNEL); + xp = xfrm_policy_alloc(net, GFP_ATOMIC); if (xp == NULL) { *dir = -ENOBUFS; return NULL; -- cgit v0.10.2 From f3d3f616e35db2ceeb11564eafd50759bb5bca8a Mon Sep 17 00:00:00 2001 From: Min Zhang Date: Sat, 14 Aug 2010 22:42:51 -0700 Subject: ipv6: remove sysctl jiffies conversion on gc_elasticity and min_adv_mss sysctl output ipv6 gc_elasticity and min_adv_mss as values divided by HZ. However, they are not in unit of jiffies, since ip6_rt_min_advmss refers to packet size and ip6_rt_fc_elasticity is used as scaler as in expire>>ip6_rt_gc_elasticity, so replace the jiffies conversion handler will regular handler for them. This has impact on scripts that are currently working assuming the divide by HZ, will yield different results with this patch in place. Signed-off-by: Min Zhang Signed-off-by: David S. Miller diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 8f2d040..d126365 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2580,7 +2580,7 @@ ctl_table ipv6_route_table_template[] = { .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec_jiffies, + .proc_handler = proc_dointvec, }, { .procname = "mtu_expires", @@ -2594,7 +2594,7 @@ ctl_table ipv6_route_table_template[] = { .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec_jiffies, + .proc_handler = proc_dointvec, }, { .procname = "gc_min_interval_ms", -- cgit v0.10.2 From f45755b8346f1a089ca7957dce5f4c3c6cb26e6f Mon Sep 17 00:00:00 2001 From: Xiaotian Feng Date: Fri, 13 Aug 2010 15:19:11 +0800 Subject: KVM: fix poison overwritten caused by using wrong xstate size fpu.state is allocated from task_xstate_cachep, the size of task_xstate_cachep is xstate_size. xstate_size is set from cpuid instruction, which is often smaller than sizeof(struct xsave_struct). kvm is using sizeof(struct xsave_struct) to fill in/out fpu.state.xsave, as what we allocated for fpu.state is xstate_size, kernel will write out of memory and caused poison/redzone/padding overwritten warnings. Signed-off-by: Xiaotian Feng Reviewed-by: Sheng Yang Cc: Thomas Gleixner Cc: Ingo Molnar Cc: "H. Peter Anvin" Cc: Suresh Siddha Cc: Brian Gerst Cc: Avi Kivity Cc: Robert Richter Cc: Sheng Yang Cc: Marcelo Tosatti Cc: Gleb Natapov Cc: Jan Kiszka Signed-off-by: Avi Kivity diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c index c4444bc..f855658 100644 --- a/arch/x86/kernel/i387.c +++ b/arch/x86/kernel/i387.c @@ -40,6 +40,7 @@ static unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu; unsigned int xstate_size; +EXPORT_SYMBOL_GPL(xstate_size); unsigned int sig_xstate_ia32_size = sizeof(struct _fpstate_ia32); static struct i387_fxsave_struct fx_scratch __cpuinitdata; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 97aab03..bb2347a 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2387,7 +2387,7 @@ static void kvm_vcpu_ioctl_x86_get_xsave(struct kvm_vcpu *vcpu, if (cpu_has_xsave) memcpy(guest_xsave->region, &vcpu->arch.guest_fpu.state->xsave, - sizeof(struct xsave_struct)); + xstate_size); else { memcpy(guest_xsave->region, &vcpu->arch.guest_fpu.state->fxsave, @@ -2405,7 +2405,7 @@ static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu, if (cpu_has_xsave) memcpy(&vcpu->arch.guest_fpu.state->xsave, - guest_xsave->region, sizeof(struct xsave_struct)); + guest_xsave->region, xstate_size); else { if (xstate_bv & ~XSTATE_FPSSE) return -EINVAL; -- cgit v0.10.2 From 3185bf8c23149f32d7e7363b84539ea50b26ecb1 Mon Sep 17 00:00:00 2001 From: Xiaotian Feng Date: Fri, 13 Aug 2010 16:23:06 +0800 Subject: KVM: destroy workqueue on kvm_create_pit() failures kernel needs to destroy workqueue if kvm_create_pit() fails, otherwise after pit is freed, the workqueue is leaked. Signed-off-by: Xiaotian Feng Cc: Avi Kivity Cc: Marcelo Tosatti Cc: Thomas Gleixner Cc: Ingo Molnar Cc: "H. Peter Anvin" Cc: Gleb Natapov Cc: "Michael S. Tsirkin" Cc: Gregory Haskins Signed-off-by: Avi Kivity diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index 0fd6378..f539c3c 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c @@ -742,7 +742,7 @@ fail: kvm_unregister_irq_mask_notifier(kvm, 0, &pit->mask_notifier); kvm_unregister_irq_ack_notifier(kvm, &pit_state->irq_ack_notifier); kvm_free_irq_source_id(kvm, pit->irq_source_id); - + destroy_workqueue(pit->wq); kfree(pit); return NULL; } -- cgit v0.10.2 From 21d93e2e29722d7832f61cc56d73fb953ee6578e Mon Sep 17 00:00:00 2001 From: Mikael Pettersson Date: Sun, 15 Aug 2010 10:47:23 +0100 Subject: ARM: 6329/1: wire up sys_accept4() on ARM sys_accept4() was added in kernel 2.6.28, but ARM was not updated to include it. The number and types of parameters is such that no ARM-specific processing is needed, so wiring up sys_accept4() just requires defining __NR_accept4 and adding a direct call in the syscall entry table. Tested with an EABI 2.6.35 kernel and Ulrich Drepper's original accept4() test program, modified to define __NR_accept4 for ARM. Using the updated unistd.h also eliminates a warning then building glibc (2.10.2 and newer) about accept4() being unimplemented. Signed-off-by: Mikael Pettersson Signed-off-by: Russell King diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h index dd2bf53..d02cfb6 100644 --- a/arch/arm/include/asm/unistd.h +++ b/arch/arm/include/asm/unistd.h @@ -392,6 +392,7 @@ #define __NR_rt_tgsigqueueinfo (__NR_SYSCALL_BASE+363) #define __NR_perf_event_open (__NR_SYSCALL_BASE+364) #define __NR_recvmmsg (__NR_SYSCALL_BASE+365) +#define __NR_accept4 (__NR_SYSCALL_BASE+366) /* * The following SWIs are ARM private. diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index 37ae301..afeb71f 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S @@ -375,6 +375,7 @@ CALL(sys_rt_tgsigqueueinfo) CALL(sys_perf_event_open) /* 365 */ CALL(sys_recvmmsg) + CALL(sys_accept4) #ifndef syscalls_counted .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls #define syscalls_counted -- cgit v0.10.2 From 41e2e8fd34fff909a0e40129f6ac4233ecfa67a9 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 13 Aug 2010 23:33:46 +0100 Subject: ARM: Tighten check for allowable CPSR values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Arve HjønnevĂ¥g Acked-by: Dima Zavin Signed-off-by: Russell King diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h index c974be8..7ce15eb 100644 --- a/arch/arm/include/asm/ptrace.h +++ b/arch/arm/include/asm/ptrace.h @@ -158,15 +158,24 @@ struct pt_regs { */ static inline int valid_user_regs(struct pt_regs *regs) { - if (user_mode(regs) && (regs->ARM_cpsr & PSR_I_BIT) == 0) { - regs->ARM_cpsr &= ~(PSR_F_BIT | PSR_A_BIT); - return 1; + unsigned long mode = regs->ARM_cpsr & MODE_MASK; + + /* + * Always clear the F (FIQ) and A (delayed abort) bits + */ + regs->ARM_cpsr &= ~(PSR_F_BIT | PSR_A_BIT); + + if ((regs->ARM_cpsr & PSR_I_BIT) == 0) { + if (mode == USR_MODE) + return 1; + if (elf_hwcap & HWCAP_26BIT && mode == USR26_MODE) + return 1; } /* * Force CPSR to something logical... */ - regs->ARM_cpsr &= PSR_f | PSR_s | (PSR_x & ~PSR_A_BIT) | PSR_T_BIT | MODE32_BIT; + regs->ARM_cpsr &= PSR_f | PSR_s | PSR_x | PSR_T_BIT | MODE32_BIT; if (!(elf_hwcap & HWCAP_26BIT)) regs->ARM_cpsr |= USR_MODE; -- cgit v0.10.2 From af4e36318edb848fcc0a8d5f75000ca00cdc7595 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Fri, 13 Aug 2010 12:42:24 +0900 Subject: nilfs2: fix list corruption after ifile creation failure If nilfs_attach_checkpoint() gets a memory allocation failure during creation of ifile, it will return without removing nilfs_sb_info struct from ns_supers list. When a concurrently mounted snapshot is unmounted or another new snapshot is mounted after that, this causes kernel oops as below: > BUG: unable to handle kernel NULL pointer dereference at (null) > IP: [] nilfs_find_sbinfo+0x74/0xa4 [nilfs2] > *pde = 00000000 > Oops: 0000 [#1] SMP > Call Trace: > [] ? nilfs_get_sb+0x165/0x532 [nilfs2] > [] ? ida_get_new_above+0x16d/0x187 > [] ? alloc_vfsmnt+0x7e/0x10a > [] ? kstrdup+0x2c/0x40 > [] ? vfs_kern_mount+0x96/0x14e > [] ? do_kern_mount+0x32/0xbd > [] ? do_mount+0x642/0x6a1 > [] ? do_page_fault+0x0/0x2d1 > [] ? copy_mount_options+0x80/0xe2 > [] ? strndup_user+0x48/0x67 > [] ? sys_mount+0x61/0x90 > [] ? sysenter_do_call+0x12/0x22 This fixes the problem. Signed-off-by: Ryusuke Konishi Tested-by: Ryusuke Konishi Cc: stable@kernel.org diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 1fa86b9..bee60c0 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -400,9 +400,10 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno) list_add(&sbi->s_list, &nilfs->ns_supers); up_write(&nilfs->ns_super_sem); + err = -ENOMEM; sbi->s_ifile = nilfs_ifile_new(sbi, nilfs->ns_inode_size); if (!sbi->s_ifile) - return -ENOMEM; + goto delist; down_read(&nilfs->ns_segctor_sem); err = nilfs_cpfile_get_checkpoint(nilfs->ns_cpfile, cno, 0, &raw_cp, @@ -433,6 +434,7 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno) nilfs_mdt_destroy(sbi->s_ifile); sbi->s_ifile = NULL; + delist: down_write(&nilfs->ns_super_sem); list_del_init(&sbi->s_list); up_write(&nilfs->ns_super_sem); -- cgit v0.10.2 From ea1a16f7168ac19d974ac51b47593b92280e7992 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sun, 15 Aug 2010 20:16:11 +0900 Subject: nilfs2: fix false warning saying one of two super blocks is broken After applying commit b2ac86e1, the following message got appeared after unclean shutdown: > NILFS warning: broken superblock. using spare superblock. This turns out to be a false message due to the change which updates two super blocks alternately. The secondary super block now can be selected if it's newer than the primary one. This kills the false warning by suppressing it if another super block is not actually broken. Signed-off-by: Ryusuke Konishi diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 37de1f0..6af1c00 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c @@ -608,11 +608,11 @@ static int nilfs_load_super_block(struct the_nilfs *nilfs, return -EINVAL; } - if (swp) { + if (!valid[!swp]) printk(KERN_WARNING "NILFS warning: broken superblock. " "using spare superblock.\n"); + if (swp) nilfs_swap_super_block(nilfs); - } nilfs->ns_sbwcount = 0; nilfs->ns_sbwtime = le64_to_cpu(sbp[0]->s_wtime); -- cgit v0.10.2 From a5ba6beb839cfa288960c92cd2668a2601c24dda Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 16 Aug 2010 08:08:48 +0200 Subject: ALSA: riptide - Fix detection / load of firmware files The detection and loading of firmeware on riptide driver has been broken due to rewrite of some codes, checking the presense wrongly. This patch fixes the logic again. Reference: kernel bug 16596 https://bugzilla.kernel.org/show_bug.cgi?id=16596 Cc: Signed-off-by: Takashi Iwai diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index f64fb7d..ad5202e 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -1224,15 +1224,14 @@ static int try_to_load_firmware(struct cmdif *cif, struct snd_riptide *chip) firmware.firmware.ASIC, firmware.firmware.CODEC, firmware.firmware.AUXDSP, firmware.firmware.PROG); + if (!chip) + return 1; + for (i = 0; i < FIRMWARE_VERSIONS; i++) { if (!memcmp(&firmware_versions[i], &firmware, sizeof(firmware))) - break; - } - if (i >= FIRMWARE_VERSIONS) - return 0; /* no match */ + return 1; /* OK */ - if (!chip) - return 1; /* OK */ + } snd_printdd("Writing Firmware\n"); if (!chip->fw_entry) { -- cgit v0.10.2 From daa3766e705c2605bd7f63b80c7742014ef9e04e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 15 Aug 2010 23:21:50 -0700 Subject: Revert "netlink: netlink_recvmsg() fix" This reverts commit 1235f504aaba2ebeabc863fdb3ceac764a317d47. It causes regressions worse than the problem it was trying to fix. Eric will try to solve the problem another way. Signed-off-by: David S. Miller diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 2cbf380..8648a99 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1406,7 +1406,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, struct netlink_sock *nlk = nlk_sk(sk); int noblock = flags&MSG_DONTWAIT; size_t copied; - struct sk_buff *skb; + struct sk_buff *skb, *frag __maybe_unused = NULL; int err; if (flags&MSG_OOB) @@ -1441,21 +1441,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, kfree_skb(skb); skb = compskb; } else { - /* - * Before setting frag_list to NULL, we must get a - * private copy of skb if shared (because of MSG_PEEK) - */ - if (skb_shared(skb)) { - struct sk_buff *nskb; - - nskb = pskb_copy(skb, GFP_KERNEL); - kfree_skb(skb); - skb = nskb; - err = -ENOMEM; - if (!skb) - goto out; - } - kfree_skb(skb_shinfo(skb)->frag_list); + frag = skb_shinfo(skb)->frag_list; skb_shinfo(skb)->frag_list = NULL; } } @@ -1492,6 +1478,10 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, if (flags & MSG_TRUNC) copied = skb->len; +#ifdef CONFIG_COMPAT_NETLINK_MESSAGES + skb_shinfo(skb)->frag_list = frag; +#endif + skb_free_datagram(sk, skb); if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) -- cgit v0.10.2 From c3e68fad88143fd1fe8fe640207fb19c0f087dbc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 16 Aug 2010 10:15:57 +0200 Subject: ALSA: hda - Add quirk for Dell Vostro 1220 model=dell-vostro is needed for Dell Vostro 1220 with Coexnat 5067. Reference: Novell bnc#631066 https://bugzilla.novell.com/show_bug.cgi?id=631066 Cc: Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 31b5d9e..c424952 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -3049,6 +3049,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x1028, 0x02f5, "Dell", CXT5066_DELL_LAPTOP), SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), + SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTO), SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO), SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5), -- cgit v0.10.2 From b2c1e07b81a126e5846dfc3d36f559d861df59f4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 16 Aug 2010 11:46:57 +0100 Subject: ASoC: Remove DSP mode support for WM8776 This is not supported by current hardware revisions. Signed-off-by: Mark Brown Acked-by: Liam Girdwood Cc: stable@kernel.org diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index 4e212ed..f8154e6 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c @@ -178,13 +178,6 @@ static int wm8776_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) case SND_SOC_DAIFMT_LEFT_J: iface |= 0x0001; break; - /* FIXME: CHECK A/B */ - case SND_SOC_DAIFMT_DSP_A: - iface |= 0x0003; - break; - case SND_SOC_DAIFMT_DSP_B: - iface |= 0x0007; - break; default: return -EINVAL; } -- cgit v0.10.2 From 83e4491818040ae6b2d9fc60434616304a101d39 Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Mon, 16 Aug 2010 16:01:28 +0200 Subject: USB HID: Add ID for eGalax Multitouch used in JooJoo tablet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The JooJoo tablet (http://thejoojoo.com/) contains an "eGalax Inc. USB TouchController", and this patch hooks it up to the egalax-touch driver. Without the patch we don't get any cursor motion, since it comes through Z/RX rather than X/Y. (The egalax-touch driver does not yet generate a correct event sequence for the "serial" protocol used by this device, though -- see the note added to the code, which comes from research by StĂ©phane Chatty.) Cc: Jiri Kosina Cc: StĂ©phane Chatty Signed-off-by: Chris Ball Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index e635199..0c52899 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1299,6 +1299,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) }, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) }, + { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) }, { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) }, diff --git a/drivers/hid/hid-egalax.c b/drivers/hid/hid-egalax.c index f44bdc0..8ca7f65 100644 --- a/drivers/hid/hid-egalax.c +++ b/drivers/hid/hid-egalax.c @@ -159,6 +159,13 @@ static int egalax_event(struct hid_device *hid, struct hid_field *field, { struct egalax_data *td = hid_get_drvdata(hid); + /* Note, eGalax has two product lines: the first is resistive and + * uses a standard parallel multitouch protocol (product ID == + * 48xx). The second is capacitive and uses an unusual "serial" + * protocol with a different message for each multitouch finger + * (product ID == 72xx). We do not yet generate a correct event + * sequence for the capacitive/serial protocol. + */ if (hid->claimed & HID_CLAIMED_INPUT) { struct input_dev *input = field->hidinput->input; @@ -246,6 +253,8 @@ static void egalax_remove(struct hid_device *hdev) static const struct hid_device_id egalax_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) }, + { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, + USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) }, { } }; MODULE_DEVICE_TABLE(hid, egalax_devices); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index d3fc13a..85c6d13 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -188,6 +188,7 @@ #define USB_VENDOR_ID_DWAV 0x0eef #define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH 0x480d +#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1 0x720c #define USB_VENDOR_ID_ELECOM 0x056e #define USB_DEVICE_ID_ELECOM_BM084 0x0061 -- cgit v0.10.2 From 5629236b31239dbaa182cb7eb39aad4d62278f7c Mon Sep 17 00:00:00 2001 From: Kulikov Vasiliy Date: Tue, 3 Aug 2010 19:44:16 +0400 Subject: x86: intel_ips: do not use PCI resources before pci_enable_device() IRQ and resource[] may not have correct values until after PCI hotplug setup occurs at pci_enable_device() time. The semantic match that finds this problem is as follows: // @@ identifier x; identifier request ~= "pci_request.*|pci_resource.*"; @@ ( * x->irq | * x->resource | * request(x, ...) ) ... *pci_enable_device(x) // Signed-off-by: Kulikov Vasiliy Reviewed-by: Jesse Barnes Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c index afe82e5..fad59b6 100644 --- a/drivers/platform/x86/intel_ips.c +++ b/drivers/platform/x86/intel_ips.c @@ -1432,6 +1432,12 @@ static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id) spin_lock_init(&ips->turbo_status_lock); + ret = pci_enable_device(dev); + if (ret) { + dev_err(&dev->dev, "can't enable PCI device, aborting\n"); + goto error_free; + } + if (!pci_resource_start(dev, 0)) { dev_err(&dev->dev, "TBAR not assigned, aborting\n"); ret = -ENXIO; @@ -1444,11 +1450,6 @@ static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id) goto error_free; } - ret = pci_enable_device(dev); - if (ret) { - dev_err(&dev->dev, "can't enable PCI device, aborting\n"); - goto error_free; - } ips->regmap = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); -- cgit v0.10.2 From 2e0ee69c214a0197e1b081ffec9c409ab2a5f094 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 5 Aug 2010 22:24:12 +0200 Subject: drivers/platform/x86: Adjust confusing if indentation The assignment of ret to -EIO appears to only make sense if the branch that it is aligned with is executed, so move it into that branch. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r disable braces4@ position p1,p2; statement S1,S2; @@ ( if (...) { ... } | if (...) S1@p1 S2@p2 ) @script:python@ p1 << r.p1; p2 << r.p2; @@ if (p1[0].column == p2[0].column): cocci.print_main("branch",p1) cocci.print_secs("after",p2) // Signed-off-by: Julia Lawall Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/asus_acpi.c b/drivers/platform/x86/asus_acpi.c index e058c2b..ca05aef 100644 --- a/drivers/platform/x86/asus_acpi.c +++ b/drivers/platform/x86/asus_acpi.c @@ -938,10 +938,11 @@ static int set_brightness(int value) /* SPLV laptop */ if (hotk->methods->brightness_set) { if (!write_acpi_int(hotk->handle, hotk->methods->brightness_set, - value, NULL)) + value, NULL)) { printk(KERN_WARNING "Asus ACPI: Error changing brightness\n"); ret = -EIO; + } goto out; } @@ -953,10 +954,11 @@ static int set_brightness(int value) hotk->methods->brightness_down, NULL, NULL); (value > 0) ? value-- : value++; - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { printk(KERN_WARNING "Asus ACPI: Error changing brightness\n"); ret = -EIO; + } } out: return ret; -- cgit v0.10.2 From 52d7ee558d3babb4918eed6769f593adc1b6616e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sun, 8 Aug 2010 00:01:12 +0200 Subject: intel_ips: potential null dereference There is a potential NULL dereference of "limits." We can just return NULL earlier to avoid it. The caller already handles NULL returns. Signed-off-by: Dan Carpenter Reviewed-by: Jesse Barnes Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c index fad59b6..9024480 100644 --- a/drivers/platform/x86/intel_ips.c +++ b/drivers/platform/x86/intel_ips.c @@ -1342,8 +1342,10 @@ static struct ips_mcp_limits *ips_detect_cpu(struct ips_driver *ips) limits = &ips_lv_limits; else if (strstr(boot_cpu_data.x86_model_id, "CPU U")) limits = &ips_ulv_limits; - else + else { dev_info(&ips->dev->dev, "No CPUID match found.\n"); + goto out; + } rdmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_power); tdp = turbo_power & TURBO_TDP_MASK; -- cgit v0.10.2 From 122f26726b5e16174bf8a707df14be1d93c49d62 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Mon, 9 Aug 2010 23:48:18 -0300 Subject: thinkpad-acpi: find ACPI video device by synthetic HID The Linux ACPI core locates the ACPI video devices for us and marks them with ACPI_VIDEO_HID. Use that information to locate the video device instead of a half-baked hunt for _BCL. This uncouples the detection of the number of backlight brightness levels on ThinkPads from the ACPI paths in vid_handle. With this change, the driver should be able to always detect whether the ThinkPad uses a 8-level or 16-level brightness scale even on newer models for which the vid_handle paths have not been updated yet. It will skip deactivated devices in the ACPI device tree, which is a change in behaviour. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 5d6119b..9d6fc4c 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -6080,13 +6080,18 @@ static struct backlight_ops ibm_backlight_data = { /* --------------------------------------------------------------------- */ +/* + * Call _BCL method of video device. On some ThinkPads this will + * switch the firmware to the ACPI brightness control mode. + */ + static int __init tpacpi_query_bcl_levels(acpi_handle handle) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *obj; int rc; - if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) { + if (ACPI_SUCCESS(acpi_evaluate_object(handle, "_BCL", NULL, &buffer))) { obj = (union acpi_object *)buffer.pointer; if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) { printk(TPACPI_ERR "Unknown _BCL data, " @@ -6103,55 +6108,22 @@ static int __init tpacpi_query_bcl_levels(acpi_handle handle) return rc; } -static acpi_status __init tpacpi_acpi_walk_find_bcl(acpi_handle handle, - u32 lvl, void *context, void **rv) -{ - char name[ACPI_PATH_SEGMENT_LENGTH]; - struct acpi_buffer buffer = { sizeof(name), &name }; - - if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) && - !strncmp("_BCL", name, sizeof(name) - 1)) { - BUG_ON(!rv || !*rv); - **(int **)rv = tpacpi_query_bcl_levels(handle); - return AE_CTRL_TERMINATE; - } else { - return AE_OK; - } -} /* * Returns 0 (no ACPI _BCL or _BCL invalid), or size of brightness map */ static unsigned int __init tpacpi_check_std_acpi_brightness_support(void) { - int status; + acpi_handle video_device; int bcl_levels = 0; - void *bcl_ptr = &bcl_levels; - if (!vid_handle) - TPACPI_ACPIHANDLE_INIT(vid); + tpacpi_acpi_handle_locate("video", ACPI_VIDEO_HID, &video_device); + if (video_device) + bcl_levels = tpacpi_query_bcl_levels(video_device); - if (!vid_handle) - return 0; - - /* - * Search for a _BCL method, and execute it. This is safe on all - * ThinkPads, and as a side-effect, _BCL will place a Lenovo Vista - * BIOS in ACPI backlight control mode. We do NOT have to care - * about calling the _BCL method in an enabled video device, any - * will do for our purposes. - */ + tp_features.bright_acpimode = (bcl_levels > 0); - status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3, - tpacpi_acpi_walk_find_bcl, NULL, NULL, - &bcl_ptr); - - if (ACPI_SUCCESS(status) && bcl_levels > 2) { - tp_features.bright_acpimode = 1; - return bcl_levels - 2; - } - - return 0; + return (bcl_levels > 2) ? (bcl_levels - 2) : 0; } /* -- cgit v0.10.2 From 217f09631a420295a9688e18aa4dbad1b385e56c Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Mon, 9 Aug 2010 23:48:19 -0300 Subject: thinkpad-acpi: untangle ACPI/vendor backlight selection acpi_video_backlight_support() already tells us if ACPI is handling backlight control through the generic ACPI handle. It is better to just trust it. While at it, adjust down a printk priority, and test earlier for brightness_enable=0. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Matthew Garrett diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index f6f8025..1565eefd 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -1024,6 +1024,10 @@ ThinkPad-specific interface. The driver will disable its native backlight brightness control interface if it detects that the standard ACPI interface is available in the ThinkPad. +If you want to use the thinkpad-acpi backlight brightness control +instead of the generic ACPI video backlight brightness control for some +reason, you should use the acpi_backlight=vendor kernel parameter. + The brightness_enable module parameter can be used to control whether the LCD brightness control feature will be enabled when available. brightness_enable=0 forces it to be disabled. brightness_enable=1 diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 9d6fc4c..b9430e8 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -6216,28 +6216,6 @@ static int __init brightness_init(struct ibm_init_struct *iibm) if (tp_features.bright_unkfw) return 1; - if (tp_features.bright_acpimode) { - if (acpi_video_backlight_support()) { - if (brightness_enable > 1) { - printk(TPACPI_NOTICE - "Standard ACPI backlight interface " - "available, not loading native one.\n"); - return 1; - } else if (brightness_enable == 1) { - printk(TPACPI_NOTICE - "Backlight control force enabled, even if standard " - "ACPI backlight interface is available\n"); - } - } else { - if (brightness_enable > 1) { - printk(TPACPI_NOTICE - "Standard ACPI backlight interface not " - "available, thinkpad_acpi native " - "brightness control enabled\n"); - } - } - } - if (!brightness_enable) { dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT, "brightness support disabled by " @@ -6245,6 +6223,26 @@ static int __init brightness_init(struct ibm_init_struct *iibm) return 1; } + if (acpi_video_backlight_support()) { + if (brightness_enable > 1) { + printk(TPACPI_INFO + "Standard ACPI backlight interface " + "available, not loading native one.\n"); + return 1; + } else if (brightness_enable == 1) { + printk(TPACPI_WARN + "Cannot enable backlight brightness support, " + "ACPI is already handling it. Refer to the " + "acpi_backlight kernel parameter\n"); + return 1; + } + } else if (tp_features.bright_acpimode && brightness_enable > 1) { + printk(TPACPI_NOTICE + "Standard ACPI backlight interface not " + "available, thinkpad_acpi native " + "brightness control enabled\n"); + } + /* * Check for module parameter bogosity, note that we * init brightness_mode to TPACPI_BRGHT_MODE_MAX in order to be -- cgit v0.10.2 From 34a656d22f5539f613b93e7a1d14b4bd53592505 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Mon, 9 Aug 2010 23:48:20 -0300 Subject: thinkpad-acpi: lock down size of hotkey keymap Use a safer coding style for the hotkey keymap. This does not fix any problems, as the current code is correct. But it might help avoid mistakes in the future. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index b9430e8..b0b66fb 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -1911,6 +1911,17 @@ enum { /* hot key scan codes (derived from ACPI DSDT) */ TP_ACPI_HOTKEYSCAN_VOLUMEDOWN, TP_ACPI_HOTKEYSCAN_MUTE, TP_ACPI_HOTKEYSCAN_THINKPAD, + TP_ACPI_HOTKEYSCAN_UNK1, + TP_ACPI_HOTKEYSCAN_UNK2, + TP_ACPI_HOTKEYSCAN_UNK3, + TP_ACPI_HOTKEYSCAN_UNK4, + TP_ACPI_HOTKEYSCAN_UNK5, + TP_ACPI_HOTKEYSCAN_UNK6, + TP_ACPI_HOTKEYSCAN_UNK7, + TP_ACPI_HOTKEYSCAN_UNK8, + + /* Hotkey keymap size */ + TPACPI_HOTKEY_MAP_LEN }; enum { /* Keys/events available through NVRAM polling */ @@ -3113,7 +3124,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) * If the above is too much to ask, don't change the keymap. * Ask the thinkpad-acpi maintainer to do it, instead. */ - static u16 ibm_keycode_map[] __initdata = { + static u16 ibm_keycode_map[TPACPI_HOTKEY_MAP_LEN] __initdata = { /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ KEY_FN_F1, KEY_FN_F2, KEY_COFFEE, KEY_SLEEP, KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, @@ -3147,7 +3158,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, }; - static u16 lenovo_keycode_map[] __initdata = { + static u16 lenovo_keycode_map[TPACPI_HOTKEY_MAP_LEN] __initdata = { /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ KEY_FN_F1, KEY_COFFEE, KEY_BATTERY, KEY_SLEEP, KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, @@ -3191,7 +3202,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, }; -#define TPACPI_HOTKEY_MAP_LEN ARRAY_SIZE(ibm_keycode_map) #define TPACPI_HOTKEY_MAP_SIZE sizeof(ibm_keycode_map) #define TPACPI_HOTKEY_MAP_TYPESIZE sizeof(ibm_keycode_map[0]) @@ -3469,7 +3479,8 @@ static bool hotkey_notify_hotkey(const u32 hkey, *send_acpi_ev = true; *ignore_acpi_ev = false; - if (scancode > 0 && scancode < 0x21) { + /* HKEY event 0x1001 is scancode 0x00 */ + if (scancode > 0 && scancode <= TPACPI_HOTKEY_MAP_LEN) { scancode--; if (!(hotkey_source_mask & (1 << scancode))) { tpacpi_input_send_key_masked(scancode); -- cgit v0.10.2 From d1e14dca6a18aa40394316c872993ae3bc7e311a Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Mon, 9 Aug 2010 23:48:21 -0300 Subject: thinkpad-acpi: add support for model-specific keymaps Use the quirks engine to select model-specific keymaps, which makes it much easier to extend should we need it. Keycodes are based on the tables at http://www.thinkwiki.org/wiki/Default_meanings_of_special_keys. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index b0b66fb..9ebe4f7 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -3093,6 +3093,8 @@ static const struct tpacpi_quirk tpacpi_hotkey_qtable[] __initconst = { TPACPI_Q_IBM('1', 'D', TPACPI_HK_Q_INIMASK), /* X22, X23, X24 */ }; +typedef u16 tpacpi_keymap_t[TPACPI_HOTKEY_MAP_LEN]; + static int __init hotkey_init(struct ibm_init_struct *iibm) { /* Requirements for changing the default keymaps: @@ -3124,9 +3126,17 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) * If the above is too much to ask, don't change the keymap. * Ask the thinkpad-acpi maintainer to do it, instead. */ - static u16 ibm_keycode_map[TPACPI_HOTKEY_MAP_LEN] __initdata = { + + enum keymap_index { + TPACPI_KEYMAP_IBM_GENERIC = 0, + TPACPI_KEYMAP_LENOVO_GENERIC, + }; + + static const tpacpi_keymap_t tpacpi_keymaps[] __initconst = { + /* Generic keymap for IBM ThinkPads */ + [TPACPI_KEYMAP_IBM_GENERIC] = { /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ - KEY_FN_F1, KEY_FN_F2, KEY_COFFEE, KEY_SLEEP, + KEY_FN_F1, KEY_BATTERY, KEY_COFFEE, KEY_SLEEP, KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND, @@ -3157,8 +3167,10 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) /* (assignments unknown, please report if found) */ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, - }; - static u16 lenovo_keycode_map[TPACPI_HOTKEY_MAP_LEN] __initdata = { + }, + + /* Generic keymap for Lenovo ThinkPads */ + [TPACPI_KEYMAP_LENOVO_GENERIC] = { /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ KEY_FN_F1, KEY_COFFEE, KEY_BATTERY, KEY_SLEEP, KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, @@ -3200,10 +3212,25 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) /* (assignments unknown, please report if found) */ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + }, }; -#define TPACPI_HOTKEY_MAP_SIZE sizeof(ibm_keycode_map) -#define TPACPI_HOTKEY_MAP_TYPESIZE sizeof(ibm_keycode_map[0]) + static const struct tpacpi_quirk tpacpi_keymap_qtable[] __initconst = { + /* Generic maps (fallback) */ + { + .vendor = PCI_VENDOR_ID_IBM, + .bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_ANY, + .quirks = TPACPI_KEYMAP_IBM_GENERIC, + }, + { + .vendor = PCI_VENDOR_ID_LENOVO, + .bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_ANY, + .quirks = TPACPI_KEYMAP_LENOVO_GENERIC, + }, + }; + +#define TPACPI_HOTKEY_MAP_SIZE sizeof(tpacpi_keymap_t) +#define TPACPI_HOTKEY_MAP_TYPESIZE sizeof(tpacpi_keymap_t[0]) int res, i; int status; @@ -3212,6 +3239,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) bool tabletsw_state = false; unsigned long quirks; + unsigned long keymap_id; vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, "initializing hotkey subdriver\n"); @@ -3352,7 +3380,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) goto err_exit; /* Set up key map */ - hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE, GFP_KERNEL); if (!hotkey_keycode_map) { @@ -3362,17 +3389,14 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) goto err_exit; } - if (tpacpi_is_lenovo()) { - dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, - "using Lenovo default hot key map\n"); - memcpy(hotkey_keycode_map, &lenovo_keycode_map, - TPACPI_HOTKEY_MAP_SIZE); - } else { - dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, - "using IBM default hot key map\n"); - memcpy(hotkey_keycode_map, &ibm_keycode_map, - TPACPI_HOTKEY_MAP_SIZE); - } + keymap_id = tpacpi_check_quirks(tpacpi_keymap_qtable, + ARRAY_SIZE(tpacpi_keymap_qtable)); + BUG_ON(keymap_id >= ARRAY_SIZE(tpacpi_keymaps)); + dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, + "using keymap number %lu\n", keymap_id); + + memcpy(hotkey_keycode_map, &tpacpi_keymaps[keymap_id], + TPACPI_HOTKEY_MAP_SIZE); input_set_capability(tpacpi_inputdev, EV_MSC, MSC_SCAN); tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE; -- cgit v0.10.2 From 2b75426282a8eb29d0a004ef0d289b0491c719be Mon Sep 17 00:00:00 2001 From: Jens Taprogge Date: Mon, 9 Aug 2010 23:48:22 -0300 Subject: thinkpad-acpi: Add KEY_CAMERA (Fn-F6) for Lenovo keyboards On the T410s and most likely other current models, Fn-F6 is labeled as Camera/Headphone key. Report key presses as KEY_CAMERA. Signed-off-by: Jens Taprogge Acked-by: Jerone Young Acked-by: Henrique de Moraes Holschuh Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 9ebe4f7..e35ed12 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -3173,7 +3173,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) [TPACPI_KEYMAP_LENOVO_GENERIC] = { /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ KEY_FN_F1, KEY_COFFEE, KEY_BATTERY, KEY_SLEEP, - KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, + KEY_WLAN, KEY_CAMERA, KEY_SWITCHVIDEOMODE, KEY_FN_F8, KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND, /* Scan codes 0x0C to 0x1F: Other ACPI HKEY hot keys */ -- cgit v0.10.2 From c3f755e3842108c1cffe570fe9802239810352b6 Mon Sep 17 00:00:00 2001 From: Victor van den Elzen Date: Sun, 15 Aug 2010 01:19:33 +0200 Subject: platform/x86: move rfkill for Dell Mini 1012 to compal-laptop Like others in the Mini series, the Dell Mini 1012 does not support the smbios hook required by dell-laptop. Signed-off-by: Victor van den Elzen Cc: stable Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c index d071ce0..097083c 100644 --- a/drivers/platform/x86/compal-laptop.c +++ b/drivers/platform/x86/compal-laptop.c @@ -841,6 +841,14 @@ static struct dmi_system_id __initdata compal_dmi_table[] = { .callback = dmi_check_cb }, { + .ident = "Dell Mini 1012", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1012"), + }, + .callback = dmi_check_cb + }, + { .ident = "Dell Inspiron 11z", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), @@ -1092,5 +1100,6 @@ MODULE_ALIAS("dmi:*:rnJHL90:rvrREFERENCE:*"); MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron910:*"); MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1010:*"); MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1011:*"); +MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1012:*"); MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1110:*"); MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1210:*"); diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index b41ed5c..4413975 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -122,6 +122,13 @@ static struct dmi_system_id __devinitdata dell_blacklist[] = { }, }, { + .ident = "Dell Mini 1012", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1012"), + }, + }, + { .ident = "Dell Inspiron 11z", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), -- cgit v0.10.2 From 0a492896ac07336c98f37ad7fab4a6387b6ada78 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 15 Aug 2010 00:26:14 -0700 Subject: sparc: Really fix "console=" for serial consoles. If a video head and keyboard are hooked up, specifying "console=ttyS0" or similar to use a serial console will not work properly. The key issue is that we must register all serial console capable devices with register_console(), otherwise the command line specified device won't be found. The sun serial drivers would only register themselves as console devices if the OpenFirmware specified console device node matched. To fix this part we now unconditionally get the serial console register by setting serial_drv->cons always. Secondarily we must not add_preferred_console() using the firmware provided console setting if the user gaven an override on the kernel command line using "console=" The "primary framebuffer" matching logic was always triggering o n openfirmware device node match, make it not when a command line override was given. Reported-by: Frans Pop Tested-by: Frans Pop Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/fb.h b/arch/sparc/include/asm/fb.h index e834880..2173432 100644 --- a/arch/sparc/include/asm/fb.h +++ b/arch/sparc/include/asm/fb.h @@ -1,5 +1,6 @@ #ifndef _SPARC_FB_H_ #define _SPARC_FB_H_ +#include #include #include #include @@ -18,6 +19,9 @@ static inline int fb_is_primary_device(struct fb_info *info) struct device *dev = info->device; struct device_node *node; + if (console_set_on_cmdline) + return 0; + node = dev->of_node; if (node && node == of_console_device) diff --git a/drivers/serial/suncore.c b/drivers/serial/suncore.c index 544f2e2..6381a02 100644 --- a/drivers/serial/suncore.c +++ b/drivers/serial/suncore.c @@ -55,7 +55,12 @@ EXPORT_SYMBOL(sunserial_unregister_minors); int sunserial_console_match(struct console *con, struct device_node *dp, struct uart_driver *drv, int line, bool ignore_line) { - if (!con || of_console_device != dp) + if (!con) + return 0; + + drv->cons = con; + + if (of_console_device != dp) return 0; if (!ignore_line) { @@ -69,12 +74,10 @@ int sunserial_console_match(struct console *con, struct device_node *dp, return 0; } - con->index = line; - drv->cons = con; - - if (!console_set_on_cmdline) + if (!console_set_on_cmdline) { + con->index = line; add_preferred_console(con->name, line, NULL); - + } return 1; } EXPORT_SYMBOL(sunserial_console_match); -- cgit v0.10.2 From b9e0ba8114583b0462cfb18b4ca01fc82894c5c0 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Wed, 11 Aug 2010 20:56:03 +0400 Subject: booting-without-of: Remove nonexistent chapters from TOC, fix numbering Marvell and GPIO bindings live in their own files, so the TOC should not mention them. Also fix chapters numbering. Signed-off-by: Anton Vorontsov Signed-off-by: Grant Likely diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt index 568fa08..302db5d 100644 --- a/Documentation/powerpc/booting-without-of.txt +++ b/Documentation/powerpc/booting-without-of.txt @@ -49,40 +49,13 @@ Table of Contents f) MDIO on GPIOs g) SPI busses - VII - Marvell Discovery mv64[345]6x System Controller chips - 1) The /system-controller node - 2) Child nodes of /system-controller - a) Marvell Discovery MDIO bus - b) Marvell Discovery ethernet controller - c) Marvell Discovery PHY nodes - d) Marvell Discovery SDMA nodes - e) Marvell Discovery BRG nodes - f) Marvell Discovery CUNIT nodes - g) Marvell Discovery MPSCROUTING nodes - h) Marvell Discovery MPSCINTR nodes - i) Marvell Discovery MPSC nodes - j) Marvell Discovery Watch Dog Timer nodes - k) Marvell Discovery I2C nodes - l) Marvell Discovery PIC (Programmable Interrupt Controller) nodes - m) Marvell Discovery MPP (Multipurpose Pins) multiplexing nodes - n) Marvell Discovery GPP (General Purpose Pins) nodes - o) Marvell Discovery PCI host bridge node - p) Marvell Discovery CPU Error nodes - q) Marvell Discovery SRAM Controller nodes - r) Marvell Discovery PCI Error Handler nodes - s) Marvell Discovery Memory Controller nodes - - VIII - Specifying interrupt information for devices + VII - Specifying interrupt information for devices 1) interrupts property 2) interrupt-parent property 3) OpenPIC Interrupt Controllers 4) ISA Interrupt Controllers - IX - Specifying GPIO information for devices - 1) gpios property - 2) gpio-controller nodes - - X - Specifying device power management information (sleep property) + VIII - Specifying device power management information (sleep property) Appendix A - Sample SOC node for MPC8540 -- cgit v0.10.2 From a8dcb878b628203f917c50b0268bba7fd146d9c0 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 16 Aug 2010 10:31:53 +0200 Subject: microblaze: Fix of/address: Merge all of the bus translation code Commit dbbdee94734bf6f1db7af42008a53655e77cab8f removed of_irq_pci_swizzle but didn't use pci_swizzle_interrupt_pin instead. Signed-off-by: Michal Simek Signed-off-by: Grant Likely diff --git a/arch/microblaze/kernel/prom_parse.c b/arch/microblaze/kernel/prom_parse.c index d33ba17..99d9b61 100644 --- a/arch/microblaze/kernel/prom_parse.c +++ b/arch/microblaze/kernel/prom_parse.c @@ -73,7 +73,7 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq) /* We can only get here if we hit a P2P bridge with no node, * let's do standard swizzling and try again */ - lspec = of_irq_pci_swizzle(PCI_SLOT(pdev->devfn), lspec); + lspec = pci_swizzle_interrupt_pin(pdev, lspec); pdev = ppdev; } -- cgit v0.10.2 From 088ab302f23bfc8abfaada32506d02d64a637b23 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 16 Aug 2010 10:31:54 +0200 Subject: microblaze: Fix of: eliminate of_device->node and dev_archdata->{of,prom}_node Commit 58f9b0b02414062eaff46716bc04b47d7e79add5 should contain this fix too. Signed-off-by: Michal Simek Signed-off-by: Grant Likely diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c index 23be25f..6ca8531a 100644 --- a/arch/microblaze/pci/pci-common.c +++ b/arch/microblaze/pci/pci-common.c @@ -1077,7 +1077,7 @@ void __devinit pcibios_setup_bus_devices(struct pci_bus *bus) struct dev_archdata *sd = &dev->dev.archdata; /* Setup OF node pointer in archdata */ - sd->of_node = pci_device_to_OF_node(dev); + dev->dev.of_node = pci_device_to_OF_node(dev); /* Fixup NUMA node as it may not be setup yet by the generic * code and is needed by the DMA init -- cgit v0.10.2 From b590cddfa6f40447158323b43a13cdae01d9a051 Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Mon, 16 Aug 2010 15:58:29 -0500 Subject: kdb: fix compile error without CONFIG_KALLSYMS If CONFIG_KGDB_KDB is set and CONFIG_KALLSYMS is not set the kernel will fail to build with the error: kernel/built-in.o: In function `kallsyms_symbol_next': kernel/debug/kdb/kdb_support.c:237: undefined reference to `kdb_walk_kallsyms' kernel/built-in.o: In function `kallsyms_symbol_complete': kernel/debug/kdb/kdb_support.c:193: undefined reference to `kdb_walk_kallsyms' The kdb_walk_kallsyms needs a #ifdef proper header to match the C implementation. This patch also fixes the compiler warnings in kdb_support.c when compiling without CONFIG_KALLSYMS set. The compiler warnings are a result of the kallsyms_lookup() macro not initializing the two of the pass by reference variables. Signed-off-by: Jason Wessel Reported-by: Michal Simek diff --git a/kernel/debug/kdb/kdb_private.h b/kernel/debug/kdb/kdb_private.h index c438f54..be775f7 100644 --- a/kernel/debug/kdb/kdb_private.h +++ b/kernel/debug/kdb/kdb_private.h @@ -255,7 +255,14 @@ extern void kdb_ps1(const struct task_struct *p); extern void kdb_print_nameval(const char *name, unsigned long val); extern void kdb_send_sig_info(struct task_struct *p, struct siginfo *info); extern void kdb_meminfo_proc_show(void); +#ifdef CONFIG_KALLSYMS extern const char *kdb_walk_kallsyms(loff_t *pos); +#else /* ! CONFIG_KALLSYMS */ +static inline const char *kdb_walk_kallsyms(loff_t *pos) +{ + return NULL; +} +#endif /* ! CONFIG_KALLSYMS */ extern char *kdb_getstr(char *, size_t, char *); /* Defines for kdb_symbol_print */ diff --git a/kernel/debug/kdb/kdb_support.c b/kernel/debug/kdb/kdb_support.c index 45344d5..6b2485d 100644 --- a/kernel/debug/kdb/kdb_support.c +++ b/kernel/debug/kdb/kdb_support.c @@ -82,8 +82,8 @@ static char *kdb_name_table[100]; /* arbitrary size */ int kdbnearsym(unsigned long addr, kdb_symtab_t *symtab) { int ret = 0; - unsigned long symbolsize; - unsigned long offset; + unsigned long symbolsize = 0; + unsigned long offset = 0; #define knt1_size 128 /* must be >= kallsyms table size */ char *knt1 = NULL; -- cgit v0.10.2 From 8c8aefce934dc45de641fe78d48ff1b7722d826a Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sat, 7 Aug 2010 11:00:59 -0700 Subject: kgdb: add missing __percpu markup in arch/x86/kernel/kgdb.c breakinfo->pev is a pointer to percpu pointer but was missing __percpu markup. Add it. Signed-off-by: Namhyung Kim Signed-off-by: Jason Wessel diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index ef10940..852b819 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c @@ -194,7 +194,7 @@ static struct hw_breakpoint { unsigned long addr; int len; int type; - struct perf_event **pev; + struct perf_event * __percpu *pev; } breakinfo[HBP_NUM]; static unsigned long early_dr7; -- cgit v0.10.2 From 787ea1c5811b11124d28c8d85f483c4cd37f5c58 Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Mon, 16 Aug 2010 15:58:30 -0500 Subject: arm,kgdb: fix GDB_MAX_REGS no longer used According to commit 22eeef4bb2a7fd225089c0044060ed1fbf091958 kgdb,arm: Individual register get/set for arm It's now replaced by DBG_MAX_REG_NUM. Signed-off-by: Eric Miao Signed-off-by: Jason Wessel diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c index 778c2f7..d6e8b4d 100644 --- a/arch/arm/kernel/kgdb.c +++ b/arch/arm/kernel/kgdb.c @@ -79,7 +79,7 @@ sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task) return; /* Initialize to zero */ - for (regno = 0; regno < GDB_MAX_REGS; regno++) + for (regno = 0; regno < DBG_MAX_REG_NUM; regno++) gdb_regs[regno] = 0; /* Otherwise, we have only some registers from switch_to() */ -- cgit v0.10.2 From fed891c89bfd8ef898c2289b34e748969bb12798 Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Mon, 16 Aug 2010 15:58:30 -0500 Subject: vt: fix regression warnings from KMS merge Fix the following new sparse warnings in vt.c introduced by the commit b45cfba4e9005d64d419718e7ff7f7cab44c1994 (vt,console,kdb: implement atomic console enter/leave functions): drivers/char/vt.c:197:5: warning: symbol 'saved_fg_console' was not declared. Should it be static? drivers/char/vt.c:198:5: warning: symbol 'saved_last_console' was not declared. Should it be static? drivers/char/vt.c:199:5: warning: symbol 'saved_want_console' was not declared. Should it be static? drivers/char/vt.c:200:5: warning: symbol 'saved_vc_mode' was not declared. Should it be static? Signed-off-by: Jason Wessel Reviewed-by: Jesse Barnes CC: Andrew Morton diff --git a/drivers/char/vt.c b/drivers/char/vt.c index c734f9b..3af1a22 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -194,10 +194,10 @@ static DECLARE_WORK(console_work, console_callback); int fg_console; int last_console; int want_console = -1; -int saved_fg_console; -int saved_last_console; -int saved_want_console; -int saved_vc_mode; +static int saved_fg_console; +static int saved_last_console; +static int saved_want_console; +static int saved_vc_mode; /* * For each existing display, we have a pointer to console currently visible -- cgit v0.10.2 From beed5336eba6a5a70c97e9f4bfff525915a25003 Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Mon, 16 Aug 2010 15:58:31 -0500 Subject: vt,console,kdb: preserve console_blanked while in kdb Commit b45cfba4e9005d64d419718e7ff7f7cab44c1994 (vt,console,kdb: implement atomic console enter/leave functions) introduced the ability to atomically change the console mode with kernel mode setting but did not preserve the state of the console_blanked variable. The console_blanked variable must be restored when executing the con_debug_leave() or further kernel mode set changes (such as using chvt X) will fail to correctly set the state of console. Signed-off-by: Jason Wessel Reviewed-by: Jesse Barnes CC: Andrew Morton diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 3af1a22..50590c7 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -198,6 +198,7 @@ static int saved_fg_console; static int saved_last_console; static int saved_want_console; static int saved_vc_mode; +static int saved_console_blanked; /* * For each existing display, we have a pointer to console currently visible @@ -3449,6 +3450,7 @@ int con_debug_enter(struct vc_data *vc) saved_last_console = last_console; saved_want_console = want_console; saved_vc_mode = vc->vc_mode; + saved_console_blanked = console_blanked; vc->vc_mode = KD_TEXT; console_blanked = 0; if (vc->vc_sw->con_debug_enter) @@ -3492,6 +3494,7 @@ int con_debug_leave(void) fg_console = saved_fg_console; last_console = saved_last_console; want_console = saved_want_console; + console_blanked = saved_console_blanked; vc_cons[fg_console].d->vc_mode = saved_vc_mode; vc = vc_cons[fg_console].d; -- cgit v0.10.2 From 60652d07a028595df5c2582e915325d643a3800d Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 16 Aug 2010 12:20:59 +1000 Subject: ata: update for of_device to platform_device replacement Signed-off-by: Stephen Rothwell Signed-off-by: Grant Likely diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c index ea24c1e..2673a3d 100644 --- a/drivers/ata/sata_dwc_460ex.c +++ b/drivers/ata/sata_dwc_460ex.c @@ -1588,7 +1588,7 @@ static const struct ata_port_info sata_dwc_port_info[] = { }, }; -static int sata_dwc_probe(struct of_device *ofdev, +static int sata_dwc_probe(struct platform_device *ofdev, const struct of_device_id *match) { struct sata_dwc_device *hsdev; @@ -1702,7 +1702,7 @@ error_out: return err; } -static int sata_dwc_remove(struct of_device *ofdev) +static int sata_dwc_remove(struct platform_device *ofdev) { struct device *dev = &ofdev->dev; struct ata_host *host = dev_get_drvdata(dev); -- cgit v0.10.2 From 8e8073a449b2e00641c095ad55bd56f43468daf9 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 16 Aug 2010 15:04:29 -0700 Subject: sparc: Hook up new fanotify and prlimit64 syscalls. The only tricky bit is the compat version of fanotify_mark, which which on 32-bit the 64-bit mark argument is passed in as "high32", "low32". Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/unistd.h b/arch/sparc/include/asm/unistd.h index d0b3b01..03eb5a8 100644 --- a/arch/sparc/include/asm/unistd.h +++ b/arch/sparc/include/asm/unistd.h @@ -397,8 +397,11 @@ #define __NR_rt_tgsigqueueinfo 326 #define __NR_perf_event_open 327 #define __NR_recvmmsg 328 +#define __NR_fanotify_init 329 +#define __NR_fanotify_mark 330 +#define __NR_prlimit64 331 -#define NR_syscalls 329 +#define NR_syscalls 332 #ifdef __32bit_syscall_numbers__ /* Sparc 32-bit only has the "setresuid32", "getresuid32" variants, diff --git a/arch/sparc/kernel/sys32.S b/arch/sparc/kernel/sys32.S index 46a76ba..44e5faf 100644 --- a/arch/sparc/kernel/sys32.S +++ b/arch/sparc/kernel/sys32.S @@ -330,6 +330,15 @@ do_sys_accept4: /* sys_accept4(int, struct sockaddr *, int *, int) */ nop nop + .globl sys32_fanotify_mark +sys32_fanotify_mark: + sethi %hi(sys_fanotify_mark), %g1 + sllx %o2, 32, %o2 + or %o2, %o3, %o2 + mov %o4, %o3 + jmpl %g1 + %lo(sys_fanotify_mark), %g0 + mov %o5, %o4 + .section __ex_table,"a" .align 4 .word 1b, __retl_efault, 2b, __retl_efault diff --git a/arch/sparc/kernel/systbls_32.S b/arch/sparc/kernel/systbls_32.S index 801fc8e..ec396e1 100644 --- a/arch/sparc/kernel/systbls_32.S +++ b/arch/sparc/kernel/systbls_32.S @@ -82,5 +82,6 @@ sys_call_table: /*310*/ .long sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate /*315*/ .long sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1 /*320*/ .long sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv -/*325*/ .long sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg +/*325*/ .long sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init +/*330*/ .long sys_fanotify_mark, sys_prlimit64 diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S index 9db058d..8cfcaa5 100644 --- a/arch/sparc/kernel/systbls_64.S +++ b/arch/sparc/kernel/systbls_64.S @@ -83,7 +83,8 @@ sys_call_table32: /*310*/ .word compat_sys_utimensat, compat_sys_signalfd, sys_timerfd_create, sys_eventfd, compat_sys_fallocate .word compat_sys_timerfd_settime, compat_sys_timerfd_gettime, compat_sys_signalfd4, sys_eventfd2, sys_epoll_create1 /*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, compat_sys_preadv - .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open, compat_sys_recvmmsg + .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open, compat_sys_recvmmsg, sys_fanotify_init +/*330*/ .word sys32_fanotify_mark, sys_prlimit64 #endif /* CONFIG_COMPAT */ @@ -158,4 +159,5 @@ sys_call_table: /*310*/ .word sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate .word sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1 /*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv - .word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg + .word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init +/*330*/ .word sys_fanotify_mark, sys_prlimit64 -- cgit v0.10.2 From 7cb4dc9fc95f89587f57f287b47e091d7806255e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 11 Aug 2010 11:28:02 +0200 Subject: AppArmor: fix task_setrlimit prototype After rlimits tree was merged we get the following errors: security/apparmor/lsm.c:663:2: warning: initialization from incompatible pointer type It is because AppArmor was merged in the meantime, but uses the old prototype. So fix it by adding struct task_struct as a first parameter of apparmor_task_setrlimit. NOTE that this is ONLY a compilation warning fix (and crashes caused by that). It needs proper handling in AppArmor depending on who is the 'task'. Signed-off-by: Jiri Slaby Signed-off-by: John Johansen Signed-off-by: James Morris diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index d5666d3..f73e2c2 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -607,8 +607,8 @@ static int apparmor_setprocattr(struct task_struct *task, char *name, return error; } -static int apparmor_task_setrlimit(unsigned int resource, - struct rlimit *new_rlim) +static int apparmor_task_setrlimit(struct task_struct *task, + unsigned int resource, struct rlimit *new_rlim) { struct aa_profile *profile = aa_current_profile(); int error = 0; -- cgit v0.10.2 From 4ca2b7120cf8ee266e6c44429ccb541d63480c4a Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sun, 8 Aug 2010 21:35:57 +0200 Subject: drm/nouveau: Don't try DDC on the dummy I2C channel. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index b1b22ba..a1473ff 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -104,7 +104,7 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, int i; for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - struct nouveau_i2c_chan *i2c; + struct nouveau_i2c_chan *i2c = NULL; struct nouveau_encoder *nv_encoder; struct drm_mode_object *obj; int id; @@ -117,7 +117,9 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, if (!obj) continue; nv_encoder = nouveau_encoder(obj_to_encoder(obj)); - i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); + + if (nv_encoder->dcb->i2c_index < 0xf) + i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); if (i2c && nouveau_probe_i2c_addr(i2c, 0x50)) { *pnv_encoder = nv_encoder; -- cgit v0.10.2 From 56dfc58ea094e7a8607786f4762c65b09cd85738 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 10 Aug 2010 10:50:13 +1000 Subject: drm/nv50: fix minor thinko from nvc0 changes Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c index 0bd407c..8461485 100644 --- a/drivers/gpu/drm/nouveau/nouveau_i2c.c +++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c @@ -163,7 +163,7 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index) if (entry->chan) return -EEXIST; - if (dev_priv->card_type == NV_C0 && entry->read >= NV50_I2C_PORTS) { + if (dev_priv->card_type >= NV_50 && entry->read >= NV50_I2C_PORTS) { NV_ERROR(dev, "unknown i2c port %d\n", entry->read); return -EINVAL; } -- cgit v0.10.2 From 415e6186f17136075f7cc825ba3835d005773637 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 23 Jul 2010 09:06:52 +1000 Subject: drm/nouveau: fix race condition when under memory pressure When VRAM is running out it's possible that the client's push buffers get evicted to main memory. When they're validated back in, the GPU may be used for the copy back to VRAM, but the existing synchronisation code only deals with inter-channel sync, not sync between PFIFO and PGRAPH on the same channel. This leads to PFIFO fetching from command buffers that haven't quite been copied by PGRAPH yet. This patch marks push buffers as so, and forces any GPU-assisted buffer moves to be done on a different channel, which triggers the correct synchronisation to happen before we submit them. Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 84f8518..f6f4477 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -36,6 +36,21 @@ #include #include +int +nouveau_bo_sync_gpu(struct nouveau_bo *nvbo, struct nouveau_channel *chan) +{ + struct nouveau_fence *prev_fence = nvbo->bo.sync_obj; + int ret; + + if (!prev_fence || nouveau_fence_channel(prev_fence) == chan) + return 0; + + spin_lock(&nvbo->bo.lock); + ret = ttm_bo_wait(&nvbo->bo, false, false, false); + spin_unlock(&nvbo->bo.lock); + return ret; +} + static void nouveau_bo_del_ttm(struct ttm_buffer_object *bo) { diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index e424bf7..1e093a0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -1165,6 +1165,7 @@ extern u16 nouveau_bo_rd16(struct nouveau_bo *nvbo, unsigned index); extern void nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val); extern u32 nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index); extern void nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val); +extern int nouveau_bo_sync_gpu(struct nouveau_bo *, struct nouveau_channel *); /* nouveau_fence.c */ struct nouveau_fence; diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 547f2c2..a915dcd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -361,16 +361,11 @@ validate_list(struct nouveau_channel *chan, struct list_head *list, list_for_each_entry(nvbo, list, entry) { struct drm_nouveau_gem_pushbuf_bo *b = &pbbo[nvbo->pbbo_index]; - struct nouveau_fence *prev_fence = nvbo->bo.sync_obj; - if (prev_fence && nouveau_fence_channel(prev_fence) != chan) { - spin_lock(&nvbo->bo.lock); - ret = ttm_bo_wait(&nvbo->bo, false, false, false); - spin_unlock(&nvbo->bo.lock); - if (unlikely(ret)) { - NV_ERROR(dev, "fail wait other chan\n"); - return ret; - } + ret = nouveau_bo_sync_gpu(nvbo, chan); + if (unlikely(ret)) { + NV_ERROR(dev, "fail pre-validate sync\n"); + return ret; } ret = nouveau_gem_set_domain(nvbo->gem, b->read_domains, @@ -381,7 +376,7 @@ validate_list(struct nouveau_channel *chan, struct list_head *list, return ret; } - nvbo->channel = chan; + nvbo->channel = (b->read_domains & (1 << 31)) ? NULL : chan; ret = ttm_bo_validate(&nvbo->bo, &nvbo->placement, false, false, false); nvbo->channel = NULL; @@ -390,6 +385,12 @@ validate_list(struct nouveau_channel *chan, struct list_head *list, return ret; } + ret = nouveau_bo_sync_gpu(nvbo, chan); + if (unlikely(ret)) { + NV_ERROR(dev, "fail post-validate sync\n"); + return ret; + } + if (nvbo->bo.offset == b->presumed.offset && ((nvbo->bo.mem.mem_type == TTM_PL_VRAM && b->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM) || @@ -615,6 +616,21 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, mutex_lock(&dev->struct_mutex); + /* Mark push buffers as being used on PFIFO, the validation code + * will then make sure that if the pushbuf bo moves, that they + * happen on the kernel channel, which will in turn cause a sync + * to happen before we try and submit the push buffer. + */ + for (i = 0; i < req->nr_push; i++) { + if (push[i].bo_index >= req->nr_buffers) { + NV_ERROR(dev, "push %d buffer not in list\n", i); + ret = -EINVAL; + goto out; + } + + bo[push[i].bo_index].read_domains |= (1 << 31); + } + /* Validate buffer list */ ret = nouveau_gem_pushbuf_validate(chan, file_priv, bo, req->buffers, req->nr_buffers, &op, &do_reloc); -- cgit v0.10.2 From bd6aaea89318bd3aede9e219d6a003afd9978d5b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 12 Aug 2010 10:23:06 +1000 Subject: drm/nouveau: check for error when allocating/mapping dummy page Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index 491767f..6b9187d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -214,6 +214,7 @@ int nouveau_sgdma_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; + struct pci_dev *pdev = dev->pdev; struct nouveau_gpuobj *gpuobj = NULL; uint32_t aper_size, obj_size; int i, ret; @@ -239,10 +240,19 @@ nouveau_sgdma_init(struct drm_device *dev) dev_priv->gart_info.sg_dummy_page = alloc_page(GFP_KERNEL|__GFP_DMA32); + if (!dev_priv->gart_info.sg_dummy_page) { + nouveau_gpuobj_del(dev, &gpuobj); + return -ENOMEM; + } + set_bit(PG_locked, &dev_priv->gart_info.sg_dummy_page->flags); dev_priv->gart_info.sg_dummy_bus = - pci_map_page(dev->pdev, dev_priv->gart_info.sg_dummy_page, 0, + pci_map_page(pdev, dev_priv->gart_info.sg_dummy_page, 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + if (pci_dma_mapping_error(pdev, dev_priv->gart_info.sg_dummy_bus)) { + nouveau_gpuobj_del(dev, &gpuobj); + return -EFAULT; + } if (dev_priv->card_type < NV_50) { /* Maybe use NV_DMA_TARGET_AGP for PCIE? NVIDIA do this, and -- cgit v0.10.2 From 98720bf4e1ba5f1d0109f97a49a9028b91f25cbe Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 13 Aug 2010 08:31:22 +1000 Subject: drm/nouveau: remove warning about unknown tmds table revisions This message is apparently confusing people, and is being blamed for some modesetting issues. Lets remove the message, and instead replace it with an unconditional printout of the table revision. Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 0b69a96..4a7bd7c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -5357,19 +5357,17 @@ static int parse_bit_tmds_tbl_entry(struct drm_device *dev, struct nvbios *bios, } tmdstableptr = ROM16(bios->data[bitentry->offset]); - - if (tmdstableptr == 0x0) { + if (!tmdstableptr) { NV_ERROR(dev, "Pointer to TMDS table invalid\n"); return -EINVAL; } + NV_INFO(dev, "TMDS table version %d.%d\n", + bios->data[tmdstableptr] >> 4, bios->data[tmdstableptr] & 0xf); + /* nv50+ has v2.0, but we don't parse it atm */ - if (bios->data[tmdstableptr] != 0x11) { - NV_WARN(dev, - "TMDS table revision %d.%d not currently supported\n", - bios->data[tmdstableptr] >> 4, bios->data[tmdstableptr] & 0xf); + if (bios->data[tmdstableptr] != 0x11) return -ENOSYS; - } /* * These two scripts are odd: they don't seem to get run even when -- cgit v0.10.2 From 45a68a072ee3b7f8fbd84b946aac827cc61256b0 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 13 Aug 2010 08:37:55 +1000 Subject: drm/nouveau: punt some more log messages to debug level Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 4a7bd7c..9e7fc1d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -4587,7 +4587,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, return 1; } - NV_TRACE(dev, "0x%04X: parsing output script 0\n", script); + NV_DEBUG_KMS(dev, "0x%04X: parsing output script 0\n", script); nouveau_bios_run_init_table(dev, script, dcbent); } else if (pxclk == -1) { @@ -4597,7 +4597,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, return 1; } - NV_TRACE(dev, "0x%04X: parsing output script 1\n", script); + NV_DEBUG_KMS(dev, "0x%04X: parsing output script 1\n", script); nouveau_bios_run_init_table(dev, script, dcbent); } else if (pxclk == -2) { @@ -4610,7 +4610,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, return 1; } - NV_TRACE(dev, "0x%04X: parsing output script 2\n", script); + NV_DEBUG_KMS(dev, "0x%04X: parsing output script 2\n", script); nouveau_bios_run_init_table(dev, script, dcbent); } else if (pxclk > 0) { @@ -4622,7 +4622,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, return 1; } - NV_TRACE(dev, "0x%04X: parsing clock script 0\n", script); + NV_DEBUG_KMS(dev, "0x%04X: parsing clock script 0\n", script); nouveau_bios_run_init_table(dev, script, dcbent); } else if (pxclk < 0) { @@ -4634,7 +4634,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, return 1; } - NV_TRACE(dev, "0x%04X: parsing clock script 1\n", script); + NV_DEBUG_KMS(dev, "0x%04X: parsing clock script 1\n", script); nouveau_bios_run_init_table(dev, script, dcbent); } -- cgit v0.10.2 From 46d4cae20038bcb2511cba0c86f0be2d11520369 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 13 Aug 2010 10:22:41 +1000 Subject: drm/nv50-nvc0: ramht_size is meant to be in bytes, not entries Fixes an infinite loop that can happen in RAMHT lookup. Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index 37c7b48..c95bf9b 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -278,7 +278,7 @@ nv50_instmem_init(struct drm_device *dev) /*XXX: incorrect, but needed to make hash func "work" */ dev_priv->ramht_offset = 0x10000; dev_priv->ramht_bits = 9; - dev_priv->ramht_size = (1 << dev_priv->ramht_bits); + dev_priv->ramht_size = (1 << dev_priv->ramht_bits) * 8; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvc0_instmem.c b/drivers/gpu/drm/nouveau/nvc0_instmem.c index 3ab3cdc..854e0d7 100644 --- a/drivers/gpu/drm/nouveau/nvc0_instmem.c +++ b/drivers/gpu/drm/nouveau/nvc0_instmem.c @@ -221,7 +221,7 @@ nvc0_instmem_init(struct drm_device *dev) /*XXX: incorrect, but needed to make hash func "work" */ dev_priv->ramht_offset = 0x10000; dev_priv->ramht_bits = 9; - dev_priv->ramht_size = (1 << dev_priv->ramht_bits); + dev_priv->ramht_size = (1 << dev_priv->ramht_bits) * 8; return 0; } -- cgit v0.10.2 From 19bf5f7df918f86a1507389101b5eddcad983951 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sat, 14 Aug 2010 18:45:58 +0200 Subject: drm/nouveau: Add TV-out quirk for an MSI nForce2 IGP. The blob also thinks there's a TV connected, so hardware bug... Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nv17_tv.c b/drivers/gpu/drm/nouveau/nv17_tv.c index 44fefb0..eefa5c8 100644 --- a/drivers/gpu/drm/nouveau/nv17_tv.c +++ b/drivers/gpu/drm/nouveau/nv17_tv.c @@ -129,6 +129,14 @@ get_tv_detect_quirks(struct drm_device *dev, uint32_t *pin_mask) return false; } + /* MSI nForce2 IGP */ + if (dev->pdev->device == 0x01f0 && + dev->pdev->subsystem_vendor == 0x1462 && + dev->pdev->subsystem_device == 0x5710) { + *pin_mask = 0xc; + return false; + } + return true; } -- cgit v0.10.2 From 20d66daf0aeae4abd2f498d0cedf3e506946f3c2 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sun, 15 Aug 2010 14:32:49 +0200 Subject: drm/nouveau: Workaround missing GPIO tables on an Apple iMac G4 NV18. This should fix the reported TV-out load detection false positives (fdo bug 29455). Reported-by: Vlado Plaga Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 9e7fc1d..e144f7a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -5807,6 +5807,22 @@ parse_dcb_gpio_table(struct nvbios *bios) gpio->line = tvdac_gpio[1] >> 4; gpio->invert = tvdac_gpio[0] & 2; } + } else { + /* + * No systematic way to store GPIO info on pre-v2.2 + * DCBs, try to match the PCI device IDs. + */ + + /* Apple iMac G4 NV18 */ + if (dev->pdev->device == 0x0189 && + dev->pdev->subsystem_vendor == 0x10de && + dev->pdev->subsystem_device == 0x0010) { + struct dcb_gpio_entry *gpio = new_gpio_entry(bios); + + gpio->tag = DCB_GPIO_TVDAC0; + gpio->line = 4; + } + } if (!gpio_table_ptr) -- cgit v0.10.2 From b515f3a2d8f8543aa189ac8d10195f923b64245b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 16 Aug 2010 08:18:16 +1000 Subject: drm/nvc0: fix thinko in instmem suspend/resume Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nvc0_instmem.c b/drivers/gpu/drm/nouveau/nvc0_instmem.c index 854e0d7..6b451f8 100644 --- a/drivers/gpu/drm/nouveau/nvc0_instmem.c +++ b/drivers/gpu/drm/nouveau/nvc0_instmem.c @@ -142,14 +142,16 @@ int nvc0_instmem_suspend(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; + u32 *buf; int i; dev_priv->susres.ramin_copy = vmalloc(65536); if (!dev_priv->susres.ramin_copy) return -ENOMEM; + buf = dev_priv->susres.ramin_copy; - for (i = 0x700000; i < 0x710000; i += 4) - dev_priv->susres.ramin_copy[i/4] = nv_rd32(dev, i); + for (i = 0; i < 65536; i += 4) + buf[i/4] = nv_rd32(dev, NV04_PRAMIN + i); return 0; } @@ -157,14 +159,15 @@ void nvc0_instmem_resume(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; + u32 *buf = dev_priv->susres.ramin_copy; u64 chan; int i; chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram; nv_wr32(dev, 0x001700, chan >> 16); - for (i = 0x700000; i < 0x710000; i += 4) - nv_wr32(dev, i, dev_priv->susres.ramin_copy[i/4]); + for (i = 0; i < 65536; i += 4) + nv_wr32(dev, NV04_PRAMIN + i, buf[i/4]); vfree(dev_priv->susres.ramin_copy); dev_priv->susres.ramin_copy = NULL; -- cgit v0.10.2 From 625db6b7e34580b750a13fd36a211a4366f6c3e2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 17 Aug 2010 12:02:43 +1000 Subject: drm/nouveau: fix earlier mistake when fixing merge conflict Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index e144f7a..e4f33a4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -2166,7 +2166,7 @@ peek_fb(struct drm_device *dev, struct io_mapping *fb, uint32_t val = 0; if (off < pci_resource_len(dev->pdev, 1)) { - uint32_t __iomem *p = + uint8_t __iomem *p = io_mapping_map_atomic_wc(fb, off & PAGE_MASK, KM_USER0); val = ioread32(p + (off & ~PAGE_MASK)); @@ -2182,7 +2182,7 @@ poke_fb(struct drm_device *dev, struct io_mapping *fb, uint32_t off, uint32_t val) { if (off < pci_resource_len(dev->pdev, 1)) { - uint32_t __iomem *p = + uint8_t __iomem *p = io_mapping_map_atomic_wc(fb, off & PAGE_MASK, KM_USER0); iowrite32(val, p + (off & ~PAGE_MASK)); -- cgit v0.10.2 From b9f0aee83335db1f3915f4e42a5e21b351740afd Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 17 Aug 2010 14:46:00 +1000 Subject: drm: stop information leak of old kernel stack. non-critical issue, CVE-2010-2803 Userspace controls the amount of memory to be allocate, so it can get the ioctl to allocate more memory than the kernel uses, and get access to kernel stack. This can only be done for processes authenticated to the X server for DRI access, and if the user has DRI access. Fix is to just memset the data to 0 if the user doesn't copy into it in the first place. Reported-by: Kees Cook Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 90288ec..3644c94 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -477,7 +477,9 @@ long drm_ioctl(struct file *filp, retcode = -EFAULT; goto err_i1; } - } + } else + memset(kdata, 0, _IOC_SIZE(cmd)); + if (ioctl->flags & DRM_UNLOCKED) retcode = func(dev, kdata, file_priv); else { -- cgit v0.10.2 From 1b2f1489633888d4a06028315dc19d65768a1c05 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 14 Aug 2010 20:20:34 +1000 Subject: drm: block userspace under allocating buffer and having drivers overwrite it (v2) With the current screwed but its ABI, ioctls for the drm, Linus pointed out that we could allow userspace to specify the allocation size, but we pass it to the driver which then uses it blindly to store a struct. Now if userspace specifies the allocation size as smaller than the driver needs, the driver can possibly overwrite memory. This patch restructures the driver ioctls so we store the structure size we are expecting, and make sure we allocate at least that size. The copy from/to userspace are still restricted to the size the user specifies, this allows ioctl structs to grow on both sides of the equation. Up until now we didn't really use the DRM_IOCTL defines in the kernel, so this cleans them up and adds them for nouveau. v2: fix nouveau pushbuf arg (thanks to Ben for pointing it out) Reported-by: Linus Torvalds Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 3644c94..84da748 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -55,6 +55,9 @@ static int drm_version(struct drm_device *dev, void *data, struct drm_file *file_priv); +#define DRM_IOCTL_DEF(ioctl, _func, _flags) \ + [DRM_IOCTL_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, .cmd_drv = 0} + /** Ioctl table */ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, 0), @@ -421,6 +424,7 @@ long drm_ioctl(struct file *filp, int retcode = -EINVAL; char stack_kdata[128]; char *kdata = NULL; + unsigned int usize, asize; dev = file_priv->minor->dev; atomic_inc(&dev->ioctl_count); @@ -436,11 +440,18 @@ long drm_ioctl(struct file *filp, ((nr < DRM_COMMAND_BASE) || (nr >= DRM_COMMAND_END))) goto err_i1; if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) && - (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) + (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) { + u32 drv_size; ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE]; + drv_size = _IOC_SIZE(ioctl->cmd_drv); + usize = asize = _IOC_SIZE(cmd); + if (drv_size > asize) + asize = drv_size; + } else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE)) { ioctl = &drm_ioctls[nr]; cmd = ioctl->cmd; + usize = asize = _IOC_SIZE(cmd); } else goto err_i1; @@ -460,10 +471,10 @@ long drm_ioctl(struct file *filp, retcode = -EACCES; } else { if (cmd & (IOC_IN | IOC_OUT)) { - if (_IOC_SIZE(cmd) <= sizeof(stack_kdata)) { + if (asize <= sizeof(stack_kdata)) { kdata = stack_kdata; } else { - kdata = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL); + kdata = kmalloc(asize, GFP_KERNEL); if (!kdata) { retcode = -ENOMEM; goto err_i1; @@ -473,12 +484,12 @@ long drm_ioctl(struct file *filp, if (cmd & IOC_IN) { if (copy_from_user(kdata, (void __user *)arg, - _IOC_SIZE(cmd)) != 0) { + usize) != 0) { retcode = -EFAULT; goto err_i1; } } else - memset(kdata, 0, _IOC_SIZE(cmd)); + memset(kdata, 0, usize); if (ioctl->flags & DRM_UNLOCKED) retcode = func(dev, kdata, file_priv); @@ -490,7 +501,7 @@ long drm_ioctl(struct file *filp, if (cmd & IOC_OUT) { if (copy_to_user((void __user *)arg, kdata, - _IOC_SIZE(cmd)) != 0) + usize) != 0) retcode = -EFAULT; } } diff --git a/drivers/gpu/drm/i810/i810_dma.c b/drivers/gpu/drm/i810/i810_dma.c index 0e6c131..61b4caf 100644 --- a/drivers/gpu/drm/i810/i810_dma.c +++ b/drivers/gpu/drm/i810/i810_dma.c @@ -1255,21 +1255,21 @@ long i810_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } struct drm_ioctl_desc i810_ioctls[] = { - DRM_IOCTL_DEF(DRM_I810_INIT, i810_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_VERTEX, i810_dma_vertex, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_CLEAR, i810_clear_bufs, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_FLUSH, i810_flush_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_GETAGE, i810_getage, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_GETBUF, i810_getbuf, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_SWAP, i810_swap_bufs, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_COPY, i810_copybuf, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_DOCOPY, i810_docopy, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_OV0INFO, i810_ov0_info, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_FSTATUS, i810_fstatus, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_OV0FLIP, i810_ov0_flip, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_MC, i810_dma_mc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_RSTATUS, i810_rstatus, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_FLIP, i810_flip_bufs, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_INIT, i810_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_VERTEX, i810_dma_vertex, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_CLEAR, i810_clear_bufs, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_FLUSH, i810_flush_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_GETAGE, i810_getage, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_GETBUF, i810_getbuf, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_SWAP, i810_swap_bufs, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_COPY, i810_copybuf, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_DOCOPY, i810_docopy, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_OV0INFO, i810_ov0_info, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_FSTATUS, i810_fstatus, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_OV0FLIP, i810_ov0_flip, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_MC, i810_dma_mc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_RSTATUS, i810_rstatus, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_FLIP, i810_flip_bufs, DRM_AUTH|DRM_UNLOCKED), }; int i810_max_ioctl = DRM_ARRAY_SIZE(i810_ioctls); diff --git a/drivers/gpu/drm/i830/i830_dma.c b/drivers/gpu/drm/i830/i830_dma.c index 5168862..671aa18 100644 --- a/drivers/gpu/drm/i830/i830_dma.c +++ b/drivers/gpu/drm/i830/i830_dma.c @@ -1524,20 +1524,20 @@ long i830_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } struct drm_ioctl_desc i830_ioctls[] = { - DRM_IOCTL_DEF(DRM_I830_INIT, i830_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I830_VERTEX, i830_dma_vertex, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I830_CLEAR, i830_clear_bufs, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I830_FLUSH, i830_flush_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I830_GETAGE, i830_getage, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I830_GETBUF, i830_getbuf, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I830_SWAP, i830_swap_bufs, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I830_COPY, i830_copybuf, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I830_DOCOPY, i830_docopy, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I830_FLIP, i830_flip_bufs, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I830_IRQ_EMIT, i830_irq_emit, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I830_IRQ_WAIT, i830_irq_wait, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I830_GETPARAM, i830_getparam, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I830_SETPARAM, i830_setparam, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_INIT, i830_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_VERTEX, i830_dma_vertex, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_CLEAR, i830_clear_bufs, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_FLUSH, i830_flush_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_GETAGE, i830_getage, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_GETBUF, i830_getbuf, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_SWAP, i830_swap_bufs, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_COPY, i830_copybuf, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_DOCOPY, i830_docopy, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_FLIP, i830_flip_bufs, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_IRQ_EMIT, i830_irq_emit, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_IRQ_WAIT, i830_irq_wait, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_GETPARAM, i830_getparam, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_SETPARAM, i830_setparam, DRM_AUTH|DRM_UNLOCKED), }; int i830_max_ioctl = DRM_ARRAY_SIZE(i830_ioctls); diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index f19ffe8..a2d3509 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2360,46 +2360,46 @@ void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv) } struct drm_ioctl_desc i915_ioctls[] = { - DRM_IOCTL_DEF(DRM_I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_I915_FLUSH, i915_flush_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_FLIP, i915_flip_bufs, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_BATCHBUFFER, i915_batchbuffer, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_IRQ_EMIT, i915_irq_emit, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_IRQ_WAIT, i915_irq_wait, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_GETPARAM, i915_getparam, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_SETPARAM, i915_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_I915_ALLOC, i915_mem_alloc, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_FREE, i915_mem_free, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_INIT_HEAP, i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_I915_CMDBUFFER, i915_cmdbuffer, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_DESTROY_HEAP, i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ), - DRM_IOCTL_DEF(DRM_I915_SET_VBLANK_PIPE, i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ), - DRM_IOCTL_DEF(DRM_I915_GET_VBLANK_PIPE, i915_vblank_pipe_get, DRM_AUTH ), - DRM_IOCTL_DEF(DRM_I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_I915_GEM_INIT, i915_gem_init_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_EXECBUFFER2, i915_gem_execbuffer2, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_UNPIN, i915_gem_unpin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_ENTERVT, i915_gem_entervt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_LEAVEVT, i915_gem_leavevt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_CREATE, i915_gem_create_ioctl, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_PREAD, i915_gem_pread_ioctl, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_PWRITE, i915_gem_pwrite_ioctl, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_MMAP, i915_gem_mmap_ioctl, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_MMAP_GTT, i915_gem_mmap_gtt_ioctl, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_SET_TILING, i915_gem_set_tiling, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_GET_TILING, i915_gem_get_tiling, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GET_PIPE_FROM_CRTC_ID, intel_get_pipe_from_crtc_id, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_MADVISE, i915_gem_madvise_ioctl, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_OVERLAY_PUT_IMAGE, intel_overlay_put_image, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_OVERLAY_ATTRS, intel_overlay_attrs, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(I915_FLUSH, i915_flush_ioctl, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_FLIP, i915_flip_bufs, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_BATCHBUFFER, i915_batchbuffer, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_IRQ_EMIT, i915_irq_emit, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_IRQ_WAIT, i915_irq_wait, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_GETPARAM, i915_getparam, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_SETPARAM, i915_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(I915_ALLOC, i915_mem_alloc, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_FREE, i915_mem_free, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_INIT_HEAP, i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(I915_CMDBUFFER, i915_cmdbuffer, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_DESTROY_HEAP, i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(I915_SET_VBLANK_PIPE, i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(I915_GET_VBLANK_PIPE, i915_vblank_pipe_get, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_HWS_ADDR, i915_set_status_page, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(I915_GEM_INIT, i915_gem_init_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER2, i915_gem_execbuffer2, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_UNPIN, i915_gem_unpin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_ENTERVT, i915_gem_entervt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_LEAVEVT, i915_gem_leavevt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_CREATE, i915_gem_create_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_PREAD, i915_gem_pread_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_PWRITE, i915_gem_pwrite_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_MMAP, i915_gem_mmap_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_MMAP_GTT, i915_gem_mmap_gtt_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_SET_TILING, i915_gem_set_tiling, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_GET_TILING, i915_gem_get_tiling, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GET_PIPE_FROM_CRTC_ID, intel_get_pipe_from_crtc_id, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_MADVISE, i915_gem_madvise_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_OVERLAY_PUT_IMAGE, intel_overlay_put_image, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_OVERLAY_ATTRS, intel_overlay_attrs, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), }; int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); diff --git a/drivers/gpu/drm/mga/mga_state.c b/drivers/gpu/drm/mga/mga_state.c index fff8204..9ce2827f 100644 --- a/drivers/gpu/drm/mga/mga_state.c +++ b/drivers/gpu/drm/mga/mga_state.c @@ -1085,19 +1085,19 @@ file_priv) } struct drm_ioctl_desc mga_ioctls[] = { - DRM_IOCTL_DEF(DRM_MGA_INIT, mga_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_MGA_FLUSH, mga_dma_flush, DRM_AUTH), - DRM_IOCTL_DEF(DRM_MGA_RESET, mga_dma_reset, DRM_AUTH), - DRM_IOCTL_DEF(DRM_MGA_SWAP, mga_dma_swap, DRM_AUTH), - DRM_IOCTL_DEF(DRM_MGA_CLEAR, mga_dma_clear, DRM_AUTH), - DRM_IOCTL_DEF(DRM_MGA_VERTEX, mga_dma_vertex, DRM_AUTH), - DRM_IOCTL_DEF(DRM_MGA_INDICES, mga_dma_indices, DRM_AUTH), - DRM_IOCTL_DEF(DRM_MGA_ILOAD, mga_dma_iload, DRM_AUTH), - DRM_IOCTL_DEF(DRM_MGA_BLIT, mga_dma_blit, DRM_AUTH), - DRM_IOCTL_DEF(DRM_MGA_GETPARAM, mga_getparam, DRM_AUTH), - DRM_IOCTL_DEF(DRM_MGA_SET_FENCE, mga_set_fence, DRM_AUTH), - DRM_IOCTL_DEF(DRM_MGA_WAIT_FENCE, mga_wait_fence, DRM_AUTH), - DRM_IOCTL_DEF(DRM_MGA_DMA_BOOTSTRAP, mga_dma_bootstrap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(MGA_INIT, mga_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(MGA_FLUSH, mga_dma_flush, DRM_AUTH), + DRM_IOCTL_DEF_DRV(MGA_RESET, mga_dma_reset, DRM_AUTH), + DRM_IOCTL_DEF_DRV(MGA_SWAP, mga_dma_swap, DRM_AUTH), + DRM_IOCTL_DEF_DRV(MGA_CLEAR, mga_dma_clear, DRM_AUTH), + DRM_IOCTL_DEF_DRV(MGA_VERTEX, mga_dma_vertex, DRM_AUTH), + DRM_IOCTL_DEF_DRV(MGA_INDICES, mga_dma_indices, DRM_AUTH), + DRM_IOCTL_DEF_DRV(MGA_ILOAD, mga_dma_iload, DRM_AUTH), + DRM_IOCTL_DEF_DRV(MGA_BLIT, mga_dma_blit, DRM_AUTH), + DRM_IOCTL_DEF_DRV(MGA_GETPARAM, mga_getparam, DRM_AUTH), + DRM_IOCTL_DEF_DRV(MGA_SET_FENCE, mga_set_fence, DRM_AUTH), + DRM_IOCTL_DEF_DRV(MGA_WAIT_FENCE, mga_wait_fence, DRM_AUTH), + DRM_IOCTL_DEF_DRV(MGA_DMA_BOOTSTRAP, mga_dma_bootstrap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), }; int mga_max_ioctl = DRM_ARRAY_SIZE(mga_ioctls); diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 90fdcda..0480f06 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -426,18 +426,18 @@ nouveau_ioctl_fifo_free(struct drm_device *dev, void *data, ***********************************/ struct drm_ioctl_desc nouveau_ioctls[] = { - DRM_IOCTL_DEF(DRM_NOUVEAU_GETPARAM, nouveau_ioctl_getparam, DRM_AUTH), - DRM_IOCTL_DEF(DRM_NOUVEAU_SETPARAM, nouveau_ioctl_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_NOUVEAU_CHANNEL_ALLOC, nouveau_ioctl_fifo_alloc, DRM_AUTH), - DRM_IOCTL_DEF(DRM_NOUVEAU_CHANNEL_FREE, nouveau_ioctl_fifo_free, DRM_AUTH), - DRM_IOCTL_DEF(DRM_NOUVEAU_GROBJ_ALLOC, nouveau_ioctl_grobj_alloc, DRM_AUTH), - DRM_IOCTL_DEF(DRM_NOUVEAU_NOTIFIEROBJ_ALLOC, nouveau_ioctl_notifier_alloc, DRM_AUTH), - DRM_IOCTL_DEF(DRM_NOUVEAU_GPUOBJ_FREE, nouveau_ioctl_gpuobj_free, DRM_AUTH), - DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_NEW, nouveau_gem_ioctl_new, DRM_AUTH), - DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_PUSHBUF, nouveau_gem_ioctl_pushbuf, DRM_AUTH), - DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_CPU_PREP, nouveau_gem_ioctl_cpu_prep, DRM_AUTH), - DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_CPU_FINI, nouveau_gem_ioctl_cpu_fini, DRM_AUTH), - DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GETPARAM, nouveau_ioctl_getparam, DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_SETPARAM, nouveau_ioctl_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_ALLOC, nouveau_ioctl_fifo_alloc, DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_FREE, nouveau_ioctl_fifo_free, DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GROBJ_ALLOC, nouveau_ioctl_grobj_alloc, DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_NOTIFIEROBJ_ALLOC, nouveau_ioctl_notifier_alloc, DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GPUOBJ_FREE, nouveau_ioctl_gpuobj_free, DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_NEW, nouveau_gem_ioctl_new, DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_PUSHBUF, nouveau_gem_ioctl_pushbuf, DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_PREP, nouveau_gem_ioctl_cpu_prep, DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_FINI, nouveau_gem_ioctl_cpu_fini, DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_AUTH), }; int nouveau_max_ioctl = DRM_ARRAY_SIZE(nouveau_ioctls); diff --git a/drivers/gpu/drm/r128/r128_state.c b/drivers/gpu/drm/r128/r128_state.c index 077af1f..a9e33ce 100644 --- a/drivers/gpu/drm/r128/r128_state.c +++ b/drivers/gpu/drm/r128/r128_state.c @@ -1639,30 +1639,29 @@ void r128_driver_preclose(struct drm_device *dev, struct drm_file *file_priv) r128_do_cleanup_pageflip(dev); } } - void r128_driver_lastclose(struct drm_device *dev) { r128_do_cleanup_cce(dev); } struct drm_ioctl_desc r128_ioctls[] = { - DRM_IOCTL_DEF(DRM_R128_INIT, r128_cce_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_R128_CCE_START, r128_cce_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_R128_CCE_STOP, r128_cce_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_R128_CCE_RESET, r128_cce_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_R128_CCE_IDLE, r128_cce_idle, DRM_AUTH), - DRM_IOCTL_DEF(DRM_R128_RESET, r128_engine_reset, DRM_AUTH), - DRM_IOCTL_DEF(DRM_R128_FULLSCREEN, r128_fullscreen, DRM_AUTH), - DRM_IOCTL_DEF(DRM_R128_SWAP, r128_cce_swap, DRM_AUTH), - DRM_IOCTL_DEF(DRM_R128_FLIP, r128_cce_flip, DRM_AUTH), - DRM_IOCTL_DEF(DRM_R128_CLEAR, r128_cce_clear, DRM_AUTH), - DRM_IOCTL_DEF(DRM_R128_VERTEX, r128_cce_vertex, DRM_AUTH), - DRM_IOCTL_DEF(DRM_R128_INDICES, r128_cce_indices, DRM_AUTH), - DRM_IOCTL_DEF(DRM_R128_BLIT, r128_cce_blit, DRM_AUTH), - DRM_IOCTL_DEF(DRM_R128_DEPTH, r128_cce_depth, DRM_AUTH), - DRM_IOCTL_DEF(DRM_R128_STIPPLE, r128_cce_stipple, DRM_AUTH), - DRM_IOCTL_DEF(DRM_R128_INDIRECT, r128_cce_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_R128_GETPARAM, r128_getparam, DRM_AUTH), + DRM_IOCTL_DEF_DRV(R128_INIT, r128_cce_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(R128_CCE_START, r128_cce_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(R128_CCE_STOP, r128_cce_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(R128_CCE_RESET, r128_cce_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(R128_CCE_IDLE, r128_cce_idle, DRM_AUTH), + DRM_IOCTL_DEF_DRV(R128_RESET, r128_engine_reset, DRM_AUTH), + DRM_IOCTL_DEF_DRV(R128_FULLSCREEN, r128_fullscreen, DRM_AUTH), + DRM_IOCTL_DEF_DRV(R128_SWAP, r128_cce_swap, DRM_AUTH), + DRM_IOCTL_DEF_DRV(R128_FLIP, r128_cce_flip, DRM_AUTH), + DRM_IOCTL_DEF_DRV(R128_CLEAR, r128_cce_clear, DRM_AUTH), + DRM_IOCTL_DEF_DRV(R128_VERTEX, r128_cce_vertex, DRM_AUTH), + DRM_IOCTL_DEF_DRV(R128_INDICES, r128_cce_indices, DRM_AUTH), + DRM_IOCTL_DEF_DRV(R128_BLIT, r128_cce_blit, DRM_AUTH), + DRM_IOCTL_DEF_DRV(R128_DEPTH, r128_cce_depth, DRM_AUTH), + DRM_IOCTL_DEF_DRV(R128_STIPPLE, r128_cce_stipple, DRM_AUTH), + DRM_IOCTL_DEF_DRV(R128_INDIRECT, r128_cce_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(R128_GETPARAM, r128_getparam, DRM_AUTH), }; int r128_max_ioctl = DRM_ARRAY_SIZE(r128_ioctls); diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index b1c8ace..27435db 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -323,45 +323,45 @@ KMS_INVALID_IOCTL(radeon_surface_free_kms) struct drm_ioctl_desc radeon_ioctls_kms[] = { - DRM_IOCTL_DEF(DRM_RADEON_CP_INIT, radeon_cp_init_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_RADEON_CP_START, radeon_cp_start_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_RADEON_CP_STOP, radeon_cp_stop_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_RADEON_CP_RESET, radeon_cp_reset_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_RADEON_CP_IDLE, radeon_cp_idle_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_CP_RESUME, radeon_cp_resume_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_RESET, radeon_engine_reset_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_FULLSCREEN, radeon_fullscreen_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_SWAP, radeon_cp_swap_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_CLEAR, radeon_cp_clear_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_VERTEX, radeon_cp_vertex_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_INDICES, radeon_cp_indices_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_TEXTURE, radeon_cp_texture_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_STIPPLE, radeon_cp_stipple_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_INDIRECT, radeon_cp_indirect_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_RADEON_VERTEX2, radeon_cp_vertex2_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_CMDBUF, radeon_cp_cmdbuf_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_GETPARAM, radeon_cp_getparam_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_FLIP, radeon_cp_flip_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_ALLOC, radeon_mem_alloc_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_FREE, radeon_mem_free_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_INIT_HEAP, radeon_mem_init_heap_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_RADEON_IRQ_EMIT, radeon_irq_emit_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_IRQ_WAIT, radeon_irq_wait_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_SETPARAM, radeon_cp_setparam_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_SURF_ALLOC, radeon_surface_alloc_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_SURF_FREE, radeon_surface_free_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_CP_INIT, radeon_cp_init_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_CP_START, radeon_cp_start_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_CP_STOP, radeon_cp_stop_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_CP_RESET, radeon_cp_reset_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_CP_IDLE, radeon_cp_idle_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_CP_RESUME, radeon_cp_resume_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_RESET, radeon_engine_reset_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_FULLSCREEN, radeon_fullscreen_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_SWAP, radeon_cp_swap_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_CLEAR, radeon_cp_clear_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_VERTEX, radeon_cp_vertex_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_INDICES, radeon_cp_indices_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_TEXTURE, radeon_cp_texture_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_STIPPLE, radeon_cp_stipple_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_INDIRECT, radeon_cp_indirect_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_VERTEX2, radeon_cp_vertex2_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_CMDBUF, radeon_cp_cmdbuf_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_GETPARAM, radeon_cp_getparam_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_FLIP, radeon_cp_flip_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_ALLOC, radeon_mem_alloc_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_FREE, radeon_mem_free_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_INIT_HEAP, radeon_mem_init_heap_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_IRQ_EMIT, radeon_irq_emit_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_IRQ_WAIT, radeon_irq_wait_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_SETPARAM, radeon_cp_setparam_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_SURF_ALLOC, radeon_surface_alloc_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_SURF_FREE, radeon_surface_free_kms, DRM_AUTH), /* KMS */ - DRM_IOCTL_DEF(DRM_RADEON_GEM_INFO, radeon_gem_info_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_RADEON_GEM_CREATE, radeon_gem_create_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_RADEON_GEM_MMAP, radeon_gem_mmap_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_RADEON_GEM_SET_DOMAIN, radeon_gem_set_domain_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_RADEON_GEM_PREAD, radeon_gem_pread_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_RADEON_GEM_PWRITE, radeon_gem_pwrite_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_RADEON_GEM_WAIT_IDLE, radeon_gem_wait_idle_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_RADEON_CS, radeon_cs_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_RADEON_INFO, radeon_info_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_RADEON_GEM_SET_TILING, radeon_gem_set_tiling_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_RADEON_GEM_GET_TILING, radeon_gem_get_tiling_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_RADEON_GEM_BUSY, radeon_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(RADEON_GEM_INFO, radeon_gem_info_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(RADEON_GEM_CREATE, radeon_gem_create_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(RADEON_GEM_MMAP, radeon_gem_mmap_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(RADEON_GEM_SET_DOMAIN, radeon_gem_set_domain_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(RADEON_GEM_PREAD, radeon_gem_pread_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(RADEON_GEM_PWRITE, radeon_gem_pwrite_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(RADEON_GEM_WAIT_IDLE, radeon_gem_wait_idle_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(RADEON_CS, radeon_cs_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(RADEON_INFO, radeon_info_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(RADEON_GEM_SET_TILING, radeon_gem_set_tiling_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(RADEON_GEM_GET_TILING, radeon_gem_get_tiling_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(RADEON_GEM_BUSY, radeon_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED), }; int radeon_max_kms_ioctl = DRM_ARRAY_SIZE(radeon_ioctls_kms); diff --git a/drivers/gpu/drm/radeon/radeon_state.c b/drivers/gpu/drm/radeon/radeon_state.c index b3ba44c0..4ae5a3d 100644 --- a/drivers/gpu/drm/radeon/radeon_state.c +++ b/drivers/gpu/drm/radeon/radeon_state.c @@ -3228,34 +3228,34 @@ void radeon_driver_postclose(struct drm_device *dev, struct drm_file *file_priv) } struct drm_ioctl_desc radeon_ioctls[] = { - DRM_IOCTL_DEF(DRM_RADEON_CP_INIT, radeon_cp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_RADEON_CP_START, radeon_cp_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_RADEON_CP_STOP, radeon_cp_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_RADEON_CP_RESET, radeon_cp_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_RADEON_CP_IDLE, radeon_cp_idle, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_CP_RESUME, radeon_cp_resume, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_RESET, radeon_engine_reset, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_FULLSCREEN, radeon_fullscreen, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_SWAP, radeon_cp_swap, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_CLEAR, radeon_cp_clear, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_VERTEX, radeon_cp_vertex, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_INDICES, radeon_cp_indices, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_TEXTURE, radeon_cp_texture, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_STIPPLE, radeon_cp_stipple, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_INDIRECT, radeon_cp_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_RADEON_VERTEX2, radeon_cp_vertex2, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_CMDBUF, radeon_cp_cmdbuf, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_GETPARAM, radeon_cp_getparam, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_FLIP, radeon_cp_flip, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_ALLOC, radeon_mem_alloc, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_FREE, radeon_mem_free, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_INIT_HEAP, radeon_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_RADEON_IRQ_EMIT, radeon_irq_emit, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_IRQ_WAIT, radeon_irq_wait, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_SETPARAM, radeon_cp_setparam, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_SURF_ALLOC, radeon_surface_alloc, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_SURF_FREE, radeon_surface_free, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_CS, r600_cs_legacy_ioctl, DRM_AUTH) + DRM_IOCTL_DEF_DRV(RADEON_CP_INIT, radeon_cp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_CP_START, radeon_cp_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_CP_STOP, radeon_cp_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_CP_RESET, radeon_cp_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_CP_IDLE, radeon_cp_idle, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_CP_RESUME, radeon_cp_resume, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_RESET, radeon_engine_reset, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_FULLSCREEN, radeon_fullscreen, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_SWAP, radeon_cp_swap, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_CLEAR, radeon_cp_clear, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_VERTEX, radeon_cp_vertex, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_INDICES, radeon_cp_indices, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_TEXTURE, radeon_cp_texture, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_STIPPLE, radeon_cp_stipple, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_INDIRECT, radeon_cp_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_VERTEX2, radeon_cp_vertex2, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_CMDBUF, radeon_cp_cmdbuf, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_GETPARAM, radeon_cp_getparam, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_FLIP, radeon_cp_flip, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_ALLOC, radeon_mem_alloc, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_FREE, radeon_mem_free, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_INIT_HEAP, radeon_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_IRQ_EMIT, radeon_irq_emit, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_IRQ_WAIT, radeon_irq_wait, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_SETPARAM, radeon_cp_setparam, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_SURF_ALLOC, radeon_surface_alloc, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_SURF_FREE, radeon_surface_free, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_CS, r600_cs_legacy_ioctl, DRM_AUTH) }; int radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls); diff --git a/drivers/gpu/drm/savage/savage_bci.c b/drivers/gpu/drm/savage/savage_bci.c index f576232..6756c97 100644 --- a/drivers/gpu/drm/savage/savage_bci.c +++ b/drivers/gpu/drm/savage/savage_bci.c @@ -1082,10 +1082,10 @@ void savage_reclaim_buffers(struct drm_device *dev, struct drm_file *file_priv) } struct drm_ioctl_desc savage_ioctls[] = { - DRM_IOCTL_DEF(DRM_SAVAGE_BCI_INIT, savage_bci_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_SAVAGE_BCI_CMDBUF, savage_bci_cmdbuf, DRM_AUTH), - DRM_IOCTL_DEF(DRM_SAVAGE_BCI_EVENT_EMIT, savage_bci_event_emit, DRM_AUTH), - DRM_IOCTL_DEF(DRM_SAVAGE_BCI_EVENT_WAIT, savage_bci_event_wait, DRM_AUTH), + DRM_IOCTL_DEF_DRV(SAVAGE_BCI_INIT, savage_bci_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(SAVAGE_BCI_CMDBUF, savage_bci_cmdbuf, DRM_AUTH), + DRM_IOCTL_DEF_DRV(SAVAGE_BCI_EVENT_EMIT, savage_bci_event_emit, DRM_AUTH), + DRM_IOCTL_DEF_DRV(SAVAGE_BCI_EVENT_WAIT, savage_bci_event_wait, DRM_AUTH), }; int savage_max_ioctl = DRM_ARRAY_SIZE(savage_ioctls); diff --git a/drivers/gpu/drm/sis/sis_mm.c b/drivers/gpu/drm/sis/sis_mm.c index 07d0f29..7fe2b63 100644 --- a/drivers/gpu/drm/sis/sis_mm.c +++ b/drivers/gpu/drm/sis/sis_mm.c @@ -320,12 +320,12 @@ void sis_reclaim_buffers_locked(struct drm_device *dev, } struct drm_ioctl_desc sis_ioctls[] = { - DRM_IOCTL_DEF(DRM_SIS_FB_ALLOC, sis_fb_alloc, DRM_AUTH), - DRM_IOCTL_DEF(DRM_SIS_FB_FREE, sis_drm_free, DRM_AUTH), - DRM_IOCTL_DEF(DRM_SIS_AGP_INIT, sis_ioctl_agp_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_SIS_AGP_ALLOC, sis_ioctl_agp_alloc, DRM_AUTH), - DRM_IOCTL_DEF(DRM_SIS_AGP_FREE, sis_drm_free, DRM_AUTH), - DRM_IOCTL_DEF(DRM_SIS_FB_INIT, sis_fb_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(SIS_FB_ALLOC, sis_fb_alloc, DRM_AUTH), + DRM_IOCTL_DEF_DRV(SIS_FB_FREE, sis_drm_free, DRM_AUTH), + DRM_IOCTL_DEF_DRV(SIS_AGP_INIT, sis_ioctl_agp_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(SIS_AGP_ALLOC, sis_ioctl_agp_alloc, DRM_AUTH), + DRM_IOCTL_DEF_DRV(SIS_AGP_FREE, sis_drm_free, DRM_AUTH), + DRM_IOCTL_DEF_DRV(SIS_FB_INIT, sis_fb_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY), }; int sis_max_ioctl = DRM_ARRAY_SIZE(sis_ioctls); diff --git a/drivers/gpu/drm/via/via_dma.c b/drivers/gpu/drm/via/via_dma.c index 68dda74..cc0ffa9 100644 --- a/drivers/gpu/drm/via/via_dma.c +++ b/drivers/gpu/drm/via/via_dma.c @@ -722,20 +722,20 @@ static int via_cmdbuf_size(struct drm_device *dev, void *data, struct drm_file * } struct drm_ioctl_desc via_ioctls[] = { - DRM_IOCTL_DEF(DRM_VIA_ALLOCMEM, via_mem_alloc, DRM_AUTH), - DRM_IOCTL_DEF(DRM_VIA_FREEMEM, via_mem_free, DRM_AUTH), - DRM_IOCTL_DEF(DRM_VIA_AGP_INIT, via_agp_init, DRM_AUTH|DRM_MASTER), - DRM_IOCTL_DEF(DRM_VIA_FB_INIT, via_fb_init, DRM_AUTH|DRM_MASTER), - DRM_IOCTL_DEF(DRM_VIA_MAP_INIT, via_map_init, DRM_AUTH|DRM_MASTER), - DRM_IOCTL_DEF(DRM_VIA_DEC_FUTEX, via_decoder_futex, DRM_AUTH), - DRM_IOCTL_DEF(DRM_VIA_DMA_INIT, via_dma_init, DRM_AUTH), - DRM_IOCTL_DEF(DRM_VIA_CMDBUFFER, via_cmdbuffer, DRM_AUTH), - DRM_IOCTL_DEF(DRM_VIA_FLUSH, via_flush_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_VIA_PCICMD, via_pci_cmdbuffer, DRM_AUTH), - DRM_IOCTL_DEF(DRM_VIA_CMDBUF_SIZE, via_cmdbuf_size, DRM_AUTH), - DRM_IOCTL_DEF(DRM_VIA_WAIT_IRQ, via_wait_irq, DRM_AUTH), - DRM_IOCTL_DEF(DRM_VIA_DMA_BLIT, via_dma_blit, DRM_AUTH), - DRM_IOCTL_DEF(DRM_VIA_BLIT_SYNC, via_dma_blit_sync, DRM_AUTH) + DRM_IOCTL_DEF_DRV(VIA_ALLOCMEM, via_mem_alloc, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_FREEMEM, via_mem_free, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_AGP_INIT, via_agp_init, DRM_AUTH|DRM_MASTER), + DRM_IOCTL_DEF_DRV(VIA_FB_INIT, via_fb_init, DRM_AUTH|DRM_MASTER), + DRM_IOCTL_DEF_DRV(VIA_MAP_INIT, via_map_init, DRM_AUTH|DRM_MASTER), + DRM_IOCTL_DEF_DRV(VIA_DEC_FUTEX, via_decoder_futex, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_DMA_INIT, via_dma_init, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_CMDBUFFER, via_cmdbuffer, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_FLUSH, via_flush_ioctl, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_PCICMD, via_pci_cmdbuffer, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_CMDBUF_SIZE, via_cmdbuf_size, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_WAIT_IRQ, via_wait_irq, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_DMA_BLIT, via_dma_blit, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_BLIT_SYNC, via_dma_blit_sync, DRM_AUTH) }; int via_max_ioctl = DRM_ARRAY_SIZE(via_ioctls); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 9dd395b..72ec2e2 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -99,47 +99,47 @@ */ #define VMW_IOCTL_DEF(ioctl, func, flags) \ - [DRM_IOCTL_NR(ioctl) - DRM_COMMAND_BASE] = {ioctl, flags, func} + [DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = {DRM_##ioctl, flags, func, DRM_IOCTL_##ioctl} /** * Ioctl definitions. */ static struct drm_ioctl_desc vmw_ioctls[] = { - VMW_IOCTL_DEF(DRM_IOCTL_VMW_GET_PARAM, vmw_getparam_ioctl, + VMW_IOCTL_DEF(VMW_GET_PARAM, vmw_getparam_ioctl, DRM_AUTH | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_ALLOC_DMABUF, vmw_dmabuf_alloc_ioctl, + VMW_IOCTL_DEF(VMW_ALLOC_DMABUF, vmw_dmabuf_alloc_ioctl, DRM_AUTH | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_UNREF_DMABUF, vmw_dmabuf_unref_ioctl, + VMW_IOCTL_DEF(VMW_UNREF_DMABUF, vmw_dmabuf_unref_ioctl, DRM_AUTH | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_CURSOR_BYPASS, + VMW_IOCTL_DEF(VMW_CURSOR_BYPASS, vmw_kms_cursor_bypass_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_CONTROL_STREAM, vmw_overlay_ioctl, + VMW_IOCTL_DEF(VMW_CONTROL_STREAM, vmw_overlay_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_CLAIM_STREAM, vmw_stream_claim_ioctl, + VMW_IOCTL_DEF(VMW_CLAIM_STREAM, vmw_stream_claim_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_UNREF_STREAM, vmw_stream_unref_ioctl, + VMW_IOCTL_DEF(VMW_UNREF_STREAM, vmw_stream_unref_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_CREATE_CONTEXT, vmw_context_define_ioctl, + VMW_IOCTL_DEF(VMW_CREATE_CONTEXT, vmw_context_define_ioctl, DRM_AUTH | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_UNREF_CONTEXT, vmw_context_destroy_ioctl, + VMW_IOCTL_DEF(VMW_UNREF_CONTEXT, vmw_context_destroy_ioctl, DRM_AUTH | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_CREATE_SURFACE, vmw_surface_define_ioctl, + VMW_IOCTL_DEF(VMW_CREATE_SURFACE, vmw_surface_define_ioctl, DRM_AUTH | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_UNREF_SURFACE, vmw_surface_destroy_ioctl, + VMW_IOCTL_DEF(VMW_UNREF_SURFACE, vmw_surface_destroy_ioctl, DRM_AUTH | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_REF_SURFACE, vmw_surface_reference_ioctl, + VMW_IOCTL_DEF(VMW_REF_SURFACE, vmw_surface_reference_ioctl, DRM_AUTH | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_EXECBUF, vmw_execbuf_ioctl, + VMW_IOCTL_DEF(VMW_EXECBUF, vmw_execbuf_ioctl, DRM_AUTH | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_FIFO_DEBUG, vmw_fifo_debug_ioctl, + VMW_IOCTL_DEF(VMW_FIFO_DEBUG, vmw_fifo_debug_ioctl, DRM_AUTH | DRM_ROOT_ONLY | DRM_MASTER | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_FENCE_WAIT, vmw_fence_wait_ioctl, + VMW_IOCTL_DEF(VMW_FENCE_WAIT, vmw_fence_wait_ioctl, DRM_AUTH | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_UPDATE_LAYOUT, vmw_kms_update_layout_ioctl, + VMW_IOCTL_DEF(VMW_UPDATE_LAYOUT, vmw_kms_update_layout_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED) }; diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 2a512bc..7809d23 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -305,14 +305,16 @@ struct drm_ioctl_desc { unsigned int cmd; int flags; drm_ioctl_t *func; + unsigned int cmd_drv; }; /** * Creates a driver or general drm_ioctl_desc array entry for the given * ioctl, for use by drm_ioctl(). */ -#define DRM_IOCTL_DEF(ioctl, _func, _flags) \ - [DRM_IOCTL_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags} + +#define DRM_IOCTL_DEF_DRV(ioctl, _func, _flags) \ + [DRM_IOCTL_NR(DRM_##ioctl)] = {.cmd = DRM_##ioctl, .func = _func, .flags = _flags, .cmd_drv = DRM_IOCTL_##ioctl} struct drm_magic_entry { struct list_head head; diff --git a/include/drm/i830_drm.h b/include/drm/i830_drm.h index 4b00d2d..61315c2 100644 --- a/include/drm/i830_drm.h +++ b/include/drm/i830_drm.h @@ -264,20 +264,20 @@ typedef struct _drm_i830_sarea { #define DRM_I830_GETPARAM 0x0c #define DRM_I830_SETPARAM 0x0d -#define DRM_IOCTL_I830_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_IOCTL_I830_INIT, drm_i830_init_t) -#define DRM_IOCTL_I830_VERTEX DRM_IOW( DRM_COMMAND_BASE + DRM_IOCTL_I830_VERTEX, drm_i830_vertex_t) -#define DRM_IOCTL_I830_CLEAR DRM_IOW( DRM_COMMAND_BASE + DRM_IOCTL_I830_CLEAR, drm_i830_clear_t) -#define DRM_IOCTL_I830_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_IOCTL_I830_FLUSH) -#define DRM_IOCTL_I830_GETAGE DRM_IO ( DRM_COMMAND_BASE + DRM_IOCTL_I830_GETAGE) -#define DRM_IOCTL_I830_GETBUF DRM_IOWR(DRM_COMMAND_BASE + DRM_IOCTL_I830_GETBUF, drm_i830_dma_t) -#define DRM_IOCTL_I830_SWAP DRM_IO ( DRM_COMMAND_BASE + DRM_IOCTL_I830_SWAP) -#define DRM_IOCTL_I830_COPY DRM_IOW( DRM_COMMAND_BASE + DRM_IOCTL_I830_COPY, drm_i830_copy_t) -#define DRM_IOCTL_I830_DOCOPY DRM_IO ( DRM_COMMAND_BASE + DRM_IOCTL_I830_DOCOPY) -#define DRM_IOCTL_I830_FLIP DRM_IO ( DRM_COMMAND_BASE + DRM_IOCTL_I830_FLIP) -#define DRM_IOCTL_I830_IRQ_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_IOCTL_I830_IRQ_EMIT, drm_i830_irq_emit_t) -#define DRM_IOCTL_I830_IRQ_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_IOCTL_I830_IRQ_WAIT, drm_i830_irq_wait_t) -#define DRM_IOCTL_I830_GETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_IOCTL_I830_GETPARAM, drm_i830_getparam_t) -#define DRM_IOCTL_I830_SETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_IOCTL_I830_SETPARAM, drm_i830_setparam_t) +#define DRM_IOCTL_I830_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I830_INIT, drm_i830_init_t) +#define DRM_IOCTL_I830_VERTEX DRM_IOW( DRM_COMMAND_BASE + DRM_I830_VERTEX, drm_i830_vertex_t) +#define DRM_IOCTL_I830_CLEAR DRM_IOW( DRM_COMMAND_BASE + DRM_I830_CLEAR, drm_i830_clear_t) +#define DRM_IOCTL_I830_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I830_FLUSH) +#define DRM_IOCTL_I830_GETAGE DRM_IO ( DRM_COMMAND_BASE + DRM_I830_GETAGE) +#define DRM_IOCTL_I830_GETBUF DRM_IOWR(DRM_COMMAND_BASE + DRM_I830_GETBUF, drm_i830_dma_t) +#define DRM_IOCTL_I830_SWAP DRM_IO ( DRM_COMMAND_BASE + DRM_I830_SWAP) +#define DRM_IOCTL_I830_COPY DRM_IOW( DRM_COMMAND_BASE + DRM_I830_COPY, drm_i830_copy_t) +#define DRM_IOCTL_I830_DOCOPY DRM_IO ( DRM_COMMAND_BASE + DRM_I830_DOCOPY) +#define DRM_IOCTL_I830_FLIP DRM_IO ( DRM_COMMAND_BASE + DRM_I830_FLIP) +#define DRM_IOCTL_I830_IRQ_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_I830_IRQ_EMIT, drm_i830_irq_emit_t) +#define DRM_IOCTL_I830_IRQ_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_I830_IRQ_WAIT, drm_i830_irq_wait_t) +#define DRM_IOCTL_I830_GETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_I830_GETPARAM, drm_i830_getparam_t) +#define DRM_IOCTL_I830_SETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_I830_SETPARAM, drm_i830_setparam_t) typedef struct _drm_i830_clear { int clear_color; diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h index 7f0028e..000357b 100644 --- a/include/drm/i915_drm.h +++ b/include/drm/i915_drm.h @@ -206,6 +206,7 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_SET_VBLANK_PIPE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t) #define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t) #define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t) +#define DRM_IOCTL_I915_HWS_ADDR DRM_IOW(DRM_COMMAND_BASE + DRM_I915_HWS_ADDR, struct drm_i915_gem_init) #define DRM_IOCTL_I915_GEM_INIT DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_INIT, struct drm_i915_gem_init) #define DRM_IOCTL_I915_GEM_EXECBUFFER DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER, struct drm_i915_gem_execbuffer) #define DRM_IOCTL_I915_GEM_EXECBUFFER2 DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER2, struct drm_i915_gem_execbuffer2) diff --git a/include/drm/mga_drm.h b/include/drm/mga_drm.h index 3ffbc47..c16097f 100644 --- a/include/drm/mga_drm.h +++ b/include/drm/mga_drm.h @@ -248,7 +248,7 @@ typedef struct _drm_mga_sarea { #define DRM_MGA_DMA_BOOTSTRAP 0x0c #define DRM_IOCTL_MGA_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_INIT, drm_mga_init_t) -#define DRM_IOCTL_MGA_FLUSH DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_FLUSH, drm_lock_t) +#define DRM_IOCTL_MGA_FLUSH DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_FLUSH, struct drm_lock) #define DRM_IOCTL_MGA_RESET DRM_IO( DRM_COMMAND_BASE + DRM_MGA_RESET) #define DRM_IOCTL_MGA_SWAP DRM_IO( DRM_COMMAND_BASE + DRM_MGA_SWAP) #define DRM_IOCTL_MGA_CLEAR DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_CLEAR, drm_mga_clear_t) diff --git a/include/drm/nouveau_drm.h b/include/drm/nouveau_drm.h index fe917de..01a7141 100644 --- a/include/drm/nouveau_drm.h +++ b/include/drm/nouveau_drm.h @@ -197,4 +197,17 @@ struct drm_nouveau_sarea { #define DRM_NOUVEAU_GEM_CPU_FINI 0x43 #define DRM_NOUVEAU_GEM_INFO 0x44 +#define DRM_IOCTL_NOUVEAU_GETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_GETPARAM, struct drm_nouveau_getparam) +#define DRM_IOCTL_NOUVEAU_SETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_SETPARAM, struct drm_nouveau_setparam) +#define DRM_IOCTL_NOUVEAU_CHANNEL_ALLOC DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_CHANNEL_ALLOC, struct drm_nouveau_channel_alloc) +#define DRM_IOCTL_NOUVEAU_CHANNEL_FREE DRM_IOW (DRM_COMMAND_BASE + DRM_NOUVEAU_CHANNEL_FREE, struct drm_nouveau_channel_free) +#define DRM_IOCTL_NOUVEAU_GROBJ_ALLOC DRM_IOW (DRM_COMMAND_BASE + DRM_NOUVEAU_GROBJ_ALLOC, struct drm_nouveau_grobj_alloc) +#define DRM_IOCTL_NOUVEAU_NOTIFIEROBJ_ALLOC DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_NOTIFIEROBJ_ALLOC, struct drm_nouveau_notifierobj_alloc) +#define DRM_IOCTL_NOUVEAU_GPUOBJ_FREE DRM_IOW (DRM_COMMAND_BASE + DRM_NOUVEAU_GPUOBJ_FREE, struct drm_nouveau_gpuobj_free) +#define DRM_IOCTL_NOUVEAU_GEM_NEW DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_GEM_NEW, struct drm_nouveau_gem_new) +#define DRM_IOCTL_NOUVEAU_GEM_PUSHBUF DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_GEM_PUSHBUF, struct drm_nouveau_gem_pushbuf) +#define DRM_IOCTL_NOUVEAU_GEM_CPU_PREP DRM_IOW (DRM_COMMAND_BASE + DRM_NOUVEAU_GEM_CPU_PREP, struct drm_nouveau_gem_cpu_prep) +#define DRM_IOCTL_NOUVEAU_GEM_CPU_FINI DRM_IOW (DRM_COMMAND_BASE + DRM_NOUVEAU_GEM_CPU_FINI, struct drm_nouveau_gem_cpu_fini) +#define DRM_IOCTL_NOUVEAU_GEM_INFO DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_GEM_INFO, struct drm_nouveau_gem_info) + #endif /* __NOUVEAU_DRM_H__ */ diff --git a/include/drm/radeon_drm.h b/include/drm/radeon_drm.h index 0acaf8f..10f8b53 100644 --- a/include/drm/radeon_drm.h +++ b/include/drm/radeon_drm.h @@ -547,8 +547,8 @@ typedef struct { #define DRM_IOCTL_RADEON_GEM_WAIT_IDLE DRM_IOW(DRM_COMMAND_BASE + DRM_RADEON_GEM_WAIT_IDLE, struct drm_radeon_gem_wait_idle) #define DRM_IOCTL_RADEON_CS DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_CS, struct drm_radeon_cs) #define DRM_IOCTL_RADEON_INFO DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_INFO, struct drm_radeon_info) -#define DRM_IOCTL_RADEON_SET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_SET_TILING, struct drm_radeon_gem_set_tiling) -#define DRM_IOCTL_RADEON_GET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_GET_TILING, struct drm_radeon_gem_get_tiling) +#define DRM_IOCTL_RADEON_GEM_SET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_SET_TILING, struct drm_radeon_gem_set_tiling) +#define DRM_IOCTL_RADEON_GEM_GET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_GET_TILING, struct drm_radeon_gem_get_tiling) #define DRM_IOCTL_RADEON_GEM_BUSY DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_BUSY, struct drm_radeon_gem_busy) typedef struct drm_radeon_init { diff --git a/include/drm/savage_drm.h b/include/drm/savage_drm.h index 8a576ef..4863cf6 100644 --- a/include/drm/savage_drm.h +++ b/include/drm/savage_drm.h @@ -63,10 +63,10 @@ typedef struct _drm_savage_sarea { #define DRM_SAVAGE_BCI_EVENT_EMIT 0x02 #define DRM_SAVAGE_BCI_EVENT_WAIT 0x03 -#define DRM_IOCTL_SAVAGE_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_INIT, drm_savage_init_t) -#define DRM_IOCTL_SAVAGE_CMDBUF DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_CMDBUF, drm_savage_cmdbuf_t) -#define DRM_IOCTL_SAVAGE_EVENT_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_SAVAGE_BCI_EVENT_EMIT, drm_savage_event_emit_t) -#define DRM_IOCTL_SAVAGE_EVENT_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_EVENT_WAIT, drm_savage_event_wait_t) +#define DRM_IOCTL_SAVAGE_BCI_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_INIT, drm_savage_init_t) +#define DRM_IOCTL_SAVAGE_BCI_CMDBUF DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_CMDBUF, drm_savage_cmdbuf_t) +#define DRM_IOCTL_SAVAGE_BCI_EVENT_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_SAVAGE_BCI_EVENT_EMIT, drm_savage_event_emit_t) +#define DRM_IOCTL_SAVAGE_BCI_EVENT_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_EVENT_WAIT, drm_savage_event_wait_t) #define SAVAGE_DMA_PCI 1 #define SAVAGE_DMA_AGP 3 -- cgit v0.10.2 From f1ca09b2b5c9dd3988c61818a7d621b1400e4f0c Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 16 Aug 2010 23:44:49 -0600 Subject: of: Fix missing includes This patch fixes missing includes from a number of .c files because the code (wrongfully) depended on prom.h including them. The include of linux/of_address.h was removed in microblaze prom.h in commit "of/address: Clean up function declarations" (sha1 id 22ae782f8), but not fixed in some callers. This patch fixes them up. Signed-off-by: Grant Likely Tested-by: Michal Simek diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c index 6ca8531a..55ef532 100644 --- a/arch/microblaze/pci/pci-common.c +++ b/arch/microblaze/pci/pci-common.c @@ -27,10 +27,11 @@ #include #include #include +#include +#include #include #include -#include #include #include diff --git a/arch/microblaze/pci/xilinx_pci.c b/arch/microblaze/pci/xilinx_pci.c index 7869a41..0687a42 100644 --- a/arch/microblaze/pci/xilinx_pci.c +++ b/arch/microblaze/pci/xilinx_pci.c @@ -16,6 +16,7 @@ #include #include +#include #include #include diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index 0ed763c..b663d57 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c @@ -94,6 +94,7 @@ #ifdef CONFIG_OF /* For open firmware. */ +#include #include #include #endif diff --git a/drivers/serial/of_serial.c b/drivers/serial/of_serial.c index 659a695..2af8fd1 100644 --- a/drivers/serial/of_serial.c +++ b/drivers/serial/of_serial.c @@ -14,11 +14,10 @@ #include #include #include +#include #include #include -#include - struct of_serial_info { int type; int line; -- cgit v0.10.2 From c69aefabe004d24e6eedf83b6f253647f77dfc43 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Tue, 17 Aug 2010 10:39:22 +0200 Subject: ALSA: hda - Fix ALC680 base model capture - Fix capture mixer elements for ALC680 base model - Support auto change ADC for recording from MIC - Cancel capture source assigned in auto mode. Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 2cd1ae8..a4dd045 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -19030,6 +19030,7 @@ static int patch_alc888(struct hda_codec *codec) /* * ALC680 support */ +#define ALC680_DIGIN_NID ALC880_DIGIN_NID #define ALC680_DIGOUT_NID ALC880_DIGOUT_NID #define alc680_modes alc260_modes @@ -19044,23 +19045,93 @@ static hda_nid_t alc680_adc_nids[3] = { 0x07, 0x08, 0x09 }; +/* + * Analog capture ADC cgange + */ +static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int pre_mic, pre_line; + + pre_mic = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_MIC]); + pre_line = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_LINE]); + + spec->cur_adc_stream_tag = stream_tag; + spec->cur_adc_format = format; + + if (pre_mic || pre_line) { + if (pre_mic) + snd_hda_codec_setup_stream(codec, 0x08, stream_tag, 0, + format); + else + snd_hda_codec_setup_stream(codec, 0x09, stream_tag, 0, + format); + } else + snd_hda_codec_setup_stream(codec, 0x07, stream_tag, 0, format); + return 0; +} + +static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + snd_hda_codec_cleanup_stream(codec, 0x07); + snd_hda_codec_cleanup_stream(codec, 0x08); + snd_hda_codec_cleanup_stream(codec, 0x09); + return 0; +} + +static struct hda_pcm_stream alc680_pcm_analog_auto_capture = { + .substreams = 1, /* can be overridden */ + .channels_min = 2, + .channels_max = 2, + /* NID is set in alc_build_pcms */ + .ops = { + .prepare = alc680_capture_pcm_prepare, + .cleanup = alc680_capture_pcm_cleanup + }, +}; + static struct snd_kcontrol_new alc680_base_mixer[] = { /* output mixer control */ HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Int Mic Boost", 0x12, 0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost", 0x19, 0, HDA_INPUT), { } }; -static struct snd_kcontrol_new alc680_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), +static struct hda_bind_ctls alc680_bind_cap_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), + 0 + }, +}; + +static struct hda_bind_ctls alc680_bind_cap_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), + 0 + }, +}; + +static struct snd_kcontrol_new alc680_master_capture_mixer[] = { + HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol), + HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch), { } /* end */ }; @@ -19068,25 +19139,73 @@ static struct snd_kcontrol_new alc680_capture_mixer[] = { * generic initialization of ADC, input mixers and output mixers */ static struct hda_verb alc680_init_verbs[] = { - /* Unmute DAC0-1 and set vol = 0 */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, + { } }; +/* toggle speaker-output according to the hp-jack state */ +static void alc680_base_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x16; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x15; + spec->autocfg.input_pins[AUTO_PIN_MIC] = 0x18; + spec->autocfg.input_pins[AUTO_PIN_LINE] = 0x19; +} + +static void alc680_rec_autoswitch(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int present; + hda_nid_t new_adc; + + present = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_MIC]); + + new_adc = present ? 0x8 : 0x7; + __snd_hda_codec_cleanup_stream(codec, !present ? 0x8 : 0x7, 1); + snd_hda_codec_setup_stream(codec, new_adc, + spec->cur_adc_stream_tag, 0, + spec->cur_adc_format); + +} + +static void alc680_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc_automute_amp(codec); + if ((res >> 26) == ALC880_MIC_EVENT) + alc680_rec_autoswitch(codec); +} + +static void alc680_inithook(struct hda_codec *codec) +{ + alc_automute_amp(codec); + alc680_rec_autoswitch(codec); +} + /* create input playback/capture controls for the given pin */ static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid, const char *ctlname, int idx) @@ -19197,13 +19316,7 @@ static void alc680_auto_init_hp_out(struct hda_codec *codec) #define alc680_pcm_analog_capture alc880_pcm_analog_capture #define alc680_pcm_analog_alt_capture alc880_pcm_analog_alt_capture #define alc680_pcm_digital_playback alc880_pcm_digital_playback - -static struct hda_input_mux alc680_capture_source = { - .num_items = 1, - .items = { - { "Mic", 0x0 }, - }, -}; +#define alc680_pcm_digital_capture alc880_pcm_digital_capture /* * BIOS auto configuration @@ -19218,6 +19331,7 @@ static int alc680_parse_auto_config(struct hda_codec *codec) alc680_ignore); if (err < 0) return err; + if (!spec->autocfg.line_outs) { if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) { spec->multiout.max_channels = 2; @@ -19239,8 +19353,6 @@ static int alc680_parse_auto_config(struct hda_codec *codec) add_mixer(spec, spec->kctls.list); add_verb(spec, alc680_init_verbs); - spec->num_mux_defs = 1; - spec->input_mux = &alc680_capture_source; err = alc_auto_add_mic_boost(codec); if (err < 0) @@ -19279,17 +19391,17 @@ static struct snd_pci_quirk alc680_cfg_tbl[] = { static struct alc_config_preset alc680_presets[] = { [ALC680_BASE] = { .mixers = { alc680_base_mixer }, - .cap_mixer = alc680_capture_mixer, + .cap_mixer = alc680_master_capture_mixer, .init_verbs = { alc680_init_verbs }, .num_dacs = ARRAY_SIZE(alc680_dac_nids), .dac_nids = alc680_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc680_adc_nids), - .adc_nids = alc680_adc_nids, - .hp_nid = 0x04, .dig_out_nid = ALC680_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc680_modes), .channel_mode = alc680_modes, - .input_mux = &alc680_capture_source, + .unsol_event = alc680_unsol_event, + .setup = alc680_base_setup, + .init_hook = alc680_inithook, + }, }; @@ -19333,9 +19445,9 @@ static int patch_alc680(struct hda_codec *codec) setup_preset(codec, &alc680_presets[board_config]); spec->stream_analog_playback = &alc680_pcm_analog_playback; - spec->stream_analog_capture = &alc680_pcm_analog_capture; - spec->stream_analog_alt_capture = &alc680_pcm_analog_alt_capture; + spec->stream_analog_capture = &alc680_pcm_analog_auto_capture; spec->stream_digital_playback = &alc680_pcm_digital_playback; + spec->stream_digital_capture = &alc680_pcm_digital_capture; if (!spec->adc_nids) { spec->adc_nids = alc680_adc_nids; -- cgit v0.10.2 From 6b5d7a9f6f7ff0e096829c1d82f70d5a6066b889 Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Tue, 17 Aug 2010 15:02:12 +0800 Subject: KVM: PIT: free irq source id in handling error path Free irq source id if create pit workqueue fail Signed-off-by: Xiao Guangrong Signed-off-by: Avi Kivity diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index f539c3c..ddeb231 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c @@ -697,6 +697,7 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags) pit->wq = create_singlethread_workqueue("kvm-pit-wq"); if (!pit->wq) { mutex_unlock(&pit->pit_state.lock); + kvm_free_irq_source_id(kvm, pit->irq_source_id); kfree(pit); return NULL; } -- cgit v0.10.2 From 3c955b407a084810f57260d61548cc92c14bc627 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Mon, 16 Aug 2010 11:58:58 +0100 Subject: fixes for using make 3.82 It doesn't like pattern and explicit rules to be on the same line, and it seems to be more picky when matching file (or really directory) names with different numbers of trailing slashes. Signed-off-by: Jan Beulich Acked-by: Sam Ravnborg Andrew Benton Cc: Signed-off-by: Michal Marek diff --git a/firmware/Makefile b/firmware/Makefile index 020e629..99955ed 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -142,7 +142,7 @@ fw-shipped-$(CONFIG_YAM) += yam/1200.bin yam/9600.bin fw-shipped-all := $(fw-shipped-y) $(fw-shipped-m) $(fw-shipped-) # Directories which we _might_ need to create, so we have a rule for them. -firmware-dirs := $(sort $(patsubst %,$(objtree)/$(obj)/%/,$(dir $(fw-external-y) $(fw-shipped-all)))) +firmware-dirs := $(sort $(addprefix $(objtree)/$(obj)/,$(dir $(fw-external-y) $(fw-shipped-all)))) quiet_cmd_mkdir = MKDIR $(patsubst $(objtree)/%,%,$@) cmd_mkdir = mkdir -p $@ diff --git a/scripts/mkmakefile b/scripts/mkmakefile index 67d59c7..5325423 100644 --- a/scripts/mkmakefile +++ b/scripts/mkmakefile @@ -44,7 +44,9 @@ all: Makefile:; -\$(all) %/: all +\$(all): all @: +%/: all + @: EOF -- cgit v0.10.2 From c206a04fba2c3890bc95dc9c20ae2cf9740fae71 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 13 Aug 2010 18:47:33 -0400 Subject: ipw2100: don't sync status queue entries These are allocated with pci_alloc_consistent, so calling pci_dma_sync_single_for_cpu is incorrect usage of the API. Remove this misuse and consequently avoid the following backtrace: WARNING: at lib/dma-debug.c:902 check_sync+0xce/0x43a() Hardware name: 2373HU6 ipw2100 0000:02:02.0: DMA-API: device driver tries to sync DMA memory it has not allocated [device address=0x0000000034e88008] [size=8 bytes] Modules linked in: microcode ipw2100(+) snd_seq_device ppdev libipw nsc_ircc snd_pcm lib80211 video output irda parport_pc cfg80211 parport thinkpad_acpi e1000 iTCO_wdt crc_ccitt snd_timer iTCO_vendor_support snd i2c_i801 pcspkr rfkill soundcore joydev snd_page_alloc yenta_socket radeon ttm drm_kms_helper drm i2c_algo_bit i2c_core [last unloaded: scsi_wait_scan] Pid: 0, comm: swapper Tainted: G W 2.6.35-wl+ #8 Call Trace: [] warn_slowpath_common+0x6a/0x7f [] ? check_sync+0xce/0x43a [] warn_slowpath_fmt+0x2b/0x2f [] check_sync+0xce/0x43a [] ? print_lock_contention_bug+0x11/0xb2 [] debug_dma_sync_single_for_cpu+0x47/0x49 [] ? ehci_irq+0x31/0x331 [] ? ipw2100_irq_tasklet+0x24/0x5e9 [ipw2100] [] ? ipw2100_irq_tasklet+0x24/0x5e9 [ipw2100] [] pci_dma_sync_single_for_cpu.clone.1+0x42/0x4b [ipw2100] [] ipw2100_irq_tasklet+0x17c/0x5e9 [ipw2100] [] tasklet_action+0x78/0xcb [] __do_softirq+0xc4/0x183 [] do_softirq+0x3b/0x5f [] irq_exit+0x3a/0x6d [] do_IRQ+0x8b/0x9f [] common_interrupt+0x35/0x3c [] ? acpi_idle_enter_simple+0xfe/0x13c [] ? exit_itimers+0x2d/0x73 [] ? acpi_idle_enter_simple+0x100/0x13c [] cpuidle_idle_call+0x78/0xdc [] cpu_idle+0x9b/0xb7 [] rest_init+0xa6/0xab [] start_kernel+0x389/0x38e [] i386_start_kernel+0xc9/0xd0 Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 1189dbb..996e9d7 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -2723,14 +2723,6 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv) packet = &priv->rx_buffers[i]; - /* Sync the DMA for the STATUS buffer so CPU is sure to get - * the correct values */ - pci_dma_sync_single_for_cpu(priv->pci_dev, - sq->nic + - sizeof(struct ipw2100_status) * i, - sizeof(struct ipw2100_status), - PCI_DMA_FROMDEVICE); - /* Sync the DMA for the RX buffer so CPU is sure to get * the correct values */ pci_dma_sync_single_for_cpu(priv->pci_dev, packet->dma_addr, -- cgit v0.10.2 From 8b8ab9d5e352aae0dcae53c657b25ab61bb73f0f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 17 Aug 2010 11:24:01 +0200 Subject: iwlwifi: fix 3945 filter flags Applying the filter flags directly as done since commit 3474ad635db371b0d8d0ee40086f15d223d5b6a4 Author: Johannes Berg Date: Thu Apr 29 04:43:05 2010 -0700 iwlwifi: apply filter flags directly broke 3945 under some unknown circumstances, as reported by Alex. Since I want to keep the direct application of filter flags on iwlagn, duplicate the code into both 3945 and agn and remove committing the RXON that broke things from the 3945 version. Cc: stable@kernel.org [2.6.35] Reported-by: Alex Romosan Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index c1882fd..10d7b9b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3667,6 +3667,49 @@ out_exit: IWL_DEBUG_MAC80211(priv, "leave\n"); } +static void iwlagn_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 multicast) +{ + struct iwl_priv *priv = hw->priv; + __le32 filter_or = 0, filter_nand = 0; + +#define CHK(test, flag) do { \ + if (*total_flags & (test)) \ + filter_or |= (flag); \ + else \ + filter_nand |= (flag); \ + } while (0) + + IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n", + changed_flags, *total_flags); + + CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK); + CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK); + CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK); + +#undef CHK + + mutex_lock(&priv->mutex); + + priv->staging_rxon.filter_flags &= ~filter_nand; + priv->staging_rxon.filter_flags |= filter_or; + + iwlcore_commit_rxon(priv); + + mutex_unlock(&priv->mutex); + + /* + * Receiving all multicast frames is always enabled by the + * default flags setup in iwl_connection_init_rx_config() + * since we currently do not support programming multicast + * filters into the device. + */ + *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS | + FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; +} + static void iwl_mac_flush(struct ieee80211_hw *hw, bool drop) { struct iwl_priv *priv = hw->priv; @@ -3867,7 +3910,7 @@ static struct ieee80211_ops iwl_hw_ops = { .add_interface = iwl_mac_add_interface, .remove_interface = iwl_mac_remove_interface, .config = iwl_mac_config, - .configure_filter = iwl_configure_filter, + .configure_filter = iwlagn_configure_filter, .set_key = iwl_mac_set_key, .update_tkip_key = iwl_mac_update_tkip_key, .conf_tx = iwl_mac_conf_tx, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 2c03c6e..07dbc27 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1328,51 +1328,6 @@ out: EXPORT_SYMBOL(iwl_apm_init); - -void iwl_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - u64 multicast) -{ - struct iwl_priv *priv = hw->priv; - __le32 filter_or = 0, filter_nand = 0; - -#define CHK(test, flag) do { \ - if (*total_flags & (test)) \ - filter_or |= (flag); \ - else \ - filter_nand |= (flag); \ - } while (0) - - IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n", - changed_flags, *total_flags); - - CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK); - CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK); - CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK); - -#undef CHK - - mutex_lock(&priv->mutex); - - priv->staging_rxon.filter_flags &= ~filter_nand; - priv->staging_rxon.filter_flags |= filter_or; - - iwlcore_commit_rxon(priv); - - mutex_unlock(&priv->mutex); - - /* - * Receiving all multicast frames is always enabled by the - * default flags setup in iwl_connection_init_rx_config() - * since we currently do not support programming multicast - * filters into the device. - */ - *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS | - FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; -} -EXPORT_SYMBOL(iwl_configure_filter); - int iwl_set_hw_params(struct iwl_priv *priv) { priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 4a71dfb..5e6ee3d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -372,9 +372,6 @@ int iwl_set_decrypted_flag(struct iwl_priv *priv, u32 decrypt_res, struct ieee80211_rx_status *stats); void iwl_irq_handle_error(struct iwl_priv *priv); -void iwl_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, u64 multicast); int iwl_set_hw_params(struct iwl_priv *priv); void iwl_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif); void iwl_bss_info_changed(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 70c4b8f..59a308b 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3391,6 +3391,55 @@ static int iwl3945_mac_sta_add(struct ieee80211_hw *hw, return 0; } + +static void iwl3945_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 multicast) +{ + struct iwl_priv *priv = hw->priv; + __le32 filter_or = 0, filter_nand = 0; + +#define CHK(test, flag) do { \ + if (*total_flags & (test)) \ + filter_or |= (flag); \ + else \ + filter_nand |= (flag); \ + } while (0) + + IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n", + changed_flags, *total_flags); + + CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK); + CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK); + CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK); + +#undef CHK + + mutex_lock(&priv->mutex); + + priv->staging_rxon.filter_flags &= ~filter_nand; + priv->staging_rxon.filter_flags |= filter_or; + + /* + * Committing directly here breaks for some reason, + * but we'll eventually commit the filter flags + * change anyway. + */ + + mutex_unlock(&priv->mutex); + + /* + * Receiving all multicast frames is always enabled by the + * default flags setup in iwl_connection_init_rx_config() + * since we currently do not support programming multicast + * filters into the device. + */ + *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS | + FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; +} + + /***************************************************************************** * * sysfs attributes @@ -3796,7 +3845,7 @@ static struct ieee80211_ops iwl3945_hw_ops = { .add_interface = iwl_mac_add_interface, .remove_interface = iwl_mac_remove_interface, .config = iwl_mac_config, - .configure_filter = iwl_configure_filter, + .configure_filter = iwl3945_configure_filter, .set_key = iwl3945_mac_set_key, .conf_tx = iwl_mac_conf_tx, .reset_tsf = iwl_mac_reset_tsf, -- cgit v0.10.2 From 7a50d06e242614f02004faed2972a8f2c9336d61 Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Tue, 17 Aug 2010 10:13:44 -0700 Subject: of: fix missing headers for of_address_to_resource() in MTD and SysACE drivers The drivers for Xilinx' SystemACE and physically mapped MTDs were missing prototypes for of_address_to_resource(). This patch adds the necessary headers. Signed-off-by: Graeme Smecher Signed-off-by: Grant Likely diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 2982b3e..057413b 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -94,6 +94,7 @@ #include #include #if defined(CONFIG_OF) +#include #include #include #endif diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index 00af55d..fe63f6b 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include -- cgit v0.10.2 From 99c796df94afca5256860dd4760017f1dbb3480c Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 17 Aug 2010 22:13:22 +0100 Subject: VIDEO: amba clcd: don't disable an already disabled clock Fix the clock enable/disable tracking in the AMBA CLCD driver so that the driver doesn't try to disable an already disabled clock, thereby causing the clock (if shared) to become unbalanced. This resolves a problem with CLCD on LPC32xx ARM platforms. Reported-by: Kevin Wells Signed-off-by: Russell King diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c index afe21e6..1c2c683 100644 --- a/drivers/video/amba-clcd.c +++ b/drivers/video/amba-clcd.c @@ -80,7 +80,10 @@ static void clcdfb_disable(struct clcd_fb *fb) /* * Disable CLCD clock source. */ - clk_disable(fb->clk); + if (fb->clk_enabled) { + fb->clk_enabled = false; + clk_disable(fb->clk); + } } static void clcdfb_enable(struct clcd_fb *fb, u32 cntl) @@ -88,7 +91,10 @@ static void clcdfb_enable(struct clcd_fb *fb, u32 cntl) /* * Enable the CLCD clock source. */ - clk_enable(fb->clk); + if (!fb->clk_enabled) { + fb->clk_enabled = true; + clk_enable(fb->clk); + } /* * Bring up by first enabling.. diff --git a/include/linux/amba/clcd.h b/include/linux/amba/clcd.h index ca16c38..be33b3a 100644 --- a/include/linux/amba/clcd.h +++ b/include/linux/amba/clcd.h @@ -150,6 +150,7 @@ struct clcd_fb { u16 off_cntl; u32 clcd_cntl; u32 cmap[16]; + bool clk_enabled; }; static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs) -- cgit v0.10.2 From df486a25900f4dba9cdc3886c4ac871951c6aef3 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 17 Aug 2010 17:42:45 -0400 Subject: NFS: Fix the selection of security flavours in Kconfig Randy Dunlap reports: ERROR: "svc_gss_principal" [fs/nfs/nfs.ko] undefined! because in fs/nfs/Kconfig, NFS_V4 selects RPCSEC_GSS_KRB5 and/or in fs/nfsd/Kconfig, NFSD_V4 selects RPCSEC_GSS_KRB5. RPCSEC_GSS_KRB5 does 5 selects, but none of these is enforced/followed by the fs/nfs[d]/Kconfig configs: select SUNRPC_GSS select CRYPTO select CRYPTO_MD5 select CRYPTO_DES select CRYPTO_CBC Reported-by: Randy Dunlap Cc: J. Bruce Fields Acked-by: Randy Dunlap Signed-off-by: Trond Myklebust diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index cc1bb33..2ddc384 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig @@ -63,7 +63,6 @@ config NFS_V3_ACL config NFS_V4 bool "NFS client support for NFS version 4" depends on NFS_FS - select RPCSEC_GSS_KRB5 help This option enables support for version 4 of the NFS protocol (RFC 3530) in the kernel's NFS client. diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig index 503b9da..95932f5 100644 --- a/fs/nfsd/Kconfig +++ b/fs/nfsd/Kconfig @@ -69,7 +69,6 @@ config NFSD_V4 depends on NFSD && PROC_FS && EXPERIMENTAL select NFSD_V3 select FS_POSIX_ACL - select RPCSEC_GSS_KRB5 help This option enables support in your system's NFS server for version 4 of the NFS protocol (RFC 3530). diff --git a/net/sunrpc/Kconfig b/net/sunrpc/Kconfig index 443c161..3376d76 100644 --- a/net/sunrpc/Kconfig +++ b/net/sunrpc/Kconfig @@ -18,10 +18,11 @@ config SUNRPC_XPRT_RDMA If unsure, say N. config RPCSEC_GSS_KRB5 - tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)" - depends on SUNRPC && EXPERIMENTAL + tristate + depends on SUNRPC && CRYPTO + prompt "Secure RPC: Kerberos V mechanism" if !(NFS_V4 || NFSD_V4) + default y select SUNRPC_GSS - select CRYPTO select CRYPTO_MD5 select CRYPTO_DES select CRYPTO_CBC @@ -34,7 +35,7 @@ config RPCSEC_GSS_KRB5 available from http://linux-nfs.org/. In addition, user-space Kerberos support should be installed. - If unsure, say N. + If unsure, say Y. config RPCSEC_GSS_SPKM3 tristate "Secure RPC: SPKM3 mechanism (EXPERIMENTAL)" -- cgit v0.10.2 From 001389b9581c13fe5fc357a0f89234f85af4215d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 16 Aug 2010 10:22:10 +0000 Subject: netfilter: {ip,ip6,arp}_tables: avoid lockdep false positive After commit 24b36f019 (netfilter: {ip,ip6,arp}_tables: dont block bottom half more than necessary), lockdep can raise a warning because we attempt to lock a spinlock with BH enabled, while the same lock is usually locked by another cpu in a softirq context. Disable again BH to avoid these lockdep warnings. Reported-by: Linus Torvalds Diagnosed-by: David S. Miller Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 6bccba3..51d6c31 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -735,6 +735,7 @@ static void get_counters(const struct xt_table_info *t, if (cpu == curcpu) continue; i = 0; + local_bh_disable(); xt_info_wrlock(cpu); xt_entry_foreach(iter, t->entries[cpu], t->size) { ADD_COUNTER(counters[i], iter->counters.bcnt, @@ -742,6 +743,7 @@ static void get_counters(const struct xt_table_info *t, ++i; } xt_info_wrunlock(cpu); + local_bh_enable(); } put_cpu(); } diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index c439721..97b64b2 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -909,6 +909,7 @@ get_counters(const struct xt_table_info *t, if (cpu == curcpu) continue; i = 0; + local_bh_disable(); xt_info_wrlock(cpu); xt_entry_foreach(iter, t->entries[cpu], t->size) { ADD_COUNTER(counters[i], iter->counters.bcnt, @@ -916,6 +917,7 @@ get_counters(const struct xt_table_info *t, ++i; /* macro does multi eval of i */ } xt_info_wrunlock(cpu); + local_bh_enable(); } put_cpu(); } diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 5359ef4..29a7bca 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -922,6 +922,7 @@ get_counters(const struct xt_table_info *t, if (cpu == curcpu) continue; i = 0; + local_bh_disable(); xt_info_wrlock(cpu); xt_entry_foreach(iter, t->entries[cpu], t->size) { ADD_COUNTER(counters[i], iter->counters.bcnt, @@ -929,6 +930,7 @@ get_counters(const struct xt_table_info *t, ++i; } xt_info_wrunlock(cpu); + local_bh_enable(); } put_cpu(); } -- cgit v0.10.2 From 1c40be12f7d8ca1d387510d39787b12e512a7ce8 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 16 Aug 2010 20:04:22 +0000 Subject: net sched: fix some kernel memory leaks We leak at least 32bits of kernel memory to user land in tc dump, because we dont init all fields (capab ?) of the dumped structure. Use C99 initializers so that holes and non explicit fields are zeroed. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c index 8406c66..c2ed90a 100644 --- a/net/sched/act_gact.c +++ b/net/sched/act_gact.c @@ -152,21 +152,24 @@ static int tcf_gact(struct sk_buff *skb, struct tc_action *a, struct tcf_result static int tcf_gact_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) { unsigned char *b = skb_tail_pointer(skb); - struct tc_gact opt; struct tcf_gact *gact = a->priv; + struct tc_gact opt = { + .index = gact->tcf_index, + .refcnt = gact->tcf_refcnt - ref, + .bindcnt = gact->tcf_bindcnt - bind, + .action = gact->tcf_action, + }; struct tcf_t t; - opt.index = gact->tcf_index; - opt.refcnt = gact->tcf_refcnt - ref; - opt.bindcnt = gact->tcf_bindcnt - bind; - opt.action = gact->tcf_action; NLA_PUT(skb, TCA_GACT_PARMS, sizeof(opt), &opt); #ifdef CONFIG_GACT_PROB if (gact->tcfg_ptype) { - struct tc_gact_p p_opt; - p_opt.paction = gact->tcfg_paction; - p_opt.pval = gact->tcfg_pval; - p_opt.ptype = gact->tcfg_ptype; + struct tc_gact_p p_opt = { + .paction = gact->tcfg_paction, + .pval = gact->tcfg_pval, + .ptype = gact->tcfg_ptype, + }; + NLA_PUT(skb, TCA_GACT_PROB, sizeof(p_opt), &p_opt); } #endif diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index 11f195a..0c311be 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -219,15 +219,16 @@ static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, i { unsigned char *b = skb_tail_pointer(skb); struct tcf_mirred *m = a->priv; - struct tc_mirred opt; + struct tc_mirred opt = { + .index = m->tcf_index, + .action = m->tcf_action, + .refcnt = m->tcf_refcnt - ref, + .bindcnt = m->tcf_bindcnt - bind, + .eaction = m->tcfm_eaction, + .ifindex = m->tcfm_ifindex, + }; struct tcf_t t; - opt.index = m->tcf_index; - opt.action = m->tcf_action; - opt.refcnt = m->tcf_refcnt - ref; - opt.bindcnt = m->tcf_bindcnt - bind; - opt.eaction = m->tcfm_eaction; - opt.ifindex = m->tcfm_ifindex; NLA_PUT(skb, TCA_MIRRED_PARMS, sizeof(opt), &opt); t.install = jiffies_to_clock_t(jiffies - m->tcf_tm.install); t.lastuse = jiffies_to_clock_t(jiffies - m->tcf_tm.lastuse); diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c index 509a2d5..186eb83 100644 --- a/net/sched/act_nat.c +++ b/net/sched/act_nat.c @@ -272,19 +272,19 @@ static int tcf_nat_dump(struct sk_buff *skb, struct tc_action *a, { unsigned char *b = skb_tail_pointer(skb); struct tcf_nat *p = a->priv; - struct tc_nat opt; + struct tc_nat opt = { + .old_addr = p->old_addr, + .new_addr = p->new_addr, + .mask = p->mask, + .flags = p->flags, + + .index = p->tcf_index, + .action = p->tcf_action, + .refcnt = p->tcf_refcnt - ref, + .bindcnt = p->tcf_bindcnt - bind, + }; struct tcf_t t; - opt.old_addr = p->old_addr; - opt.new_addr = p->new_addr; - opt.mask = p->mask; - opt.flags = p->flags; - - opt.index = p->tcf_index; - opt.action = p->tcf_action; - opt.refcnt = p->tcf_refcnt - ref; - opt.bindcnt = p->tcf_bindcnt - bind; - NLA_PUT(skb, TCA_NAT_PARMS, sizeof(opt), &opt); t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install); t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse); diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c index 4a1d640..97e84f3 100644 --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c @@ -164,13 +164,14 @@ static inline int tcf_simp_dump(struct sk_buff *skb, struct tc_action *a, { unsigned char *b = skb_tail_pointer(skb); struct tcf_defact *d = a->priv; - struct tc_defact opt; + struct tc_defact opt = { + .index = d->tcf_index, + .refcnt = d->tcf_refcnt - ref, + .bindcnt = d->tcf_bindcnt - bind, + .action = d->tcf_action, + }; struct tcf_t t; - opt.index = d->tcf_index; - opt.refcnt = d->tcf_refcnt - ref; - opt.bindcnt = d->tcf_bindcnt - bind; - opt.action = d->tcf_action; NLA_PUT(skb, TCA_DEF_PARMS, sizeof(opt), &opt); NLA_PUT_STRING(skb, TCA_DEF_DATA, d->tcfd_defdata); t.install = jiffies_to_clock_t(jiffies - d->tcf_tm.install); diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c index e9607fe..66cbf4e 100644 --- a/net/sched/act_skbedit.c +++ b/net/sched/act_skbedit.c @@ -159,13 +159,14 @@ static inline int tcf_skbedit_dump(struct sk_buff *skb, struct tc_action *a, { unsigned char *b = skb_tail_pointer(skb); struct tcf_skbedit *d = a->priv; - struct tc_skbedit opt; + struct tc_skbedit opt = { + .index = d->tcf_index, + .refcnt = d->tcf_refcnt - ref, + .bindcnt = d->tcf_bindcnt - bind, + .action = d->tcf_action, + }; struct tcf_t t; - opt.index = d->tcf_index; - opt.refcnt = d->tcf_refcnt - ref; - opt.bindcnt = d->tcf_bindcnt - bind; - opt.action = d->tcf_action; NLA_PUT(skb, TCA_SKBEDIT_PARMS, sizeof(opt), &opt); if (d->flags & SKBEDIT_F_PRIORITY) NLA_PUT(skb, TCA_SKBEDIT_PRIORITY, sizeof(d->priority), -- cgit v0.10.2 From ef201bebe5afc91a2b99b45dacc8c6dd88ca9e58 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 17 Aug 2010 17:09:53 -0700 Subject: sparc64: Fix rwsem constant bug leading to hangs. As noticed by Linus, it is critical that some of the rwsem constants be signed. Yet, hex constants are unsigned unless explicitly casted or negated. The most critical one is RWSEM_WAITING_BIAS. This bug was exacerbated by commit 424acaaeb3a3932d64a9b4bd59df6cf72c22d8f3 ("rwsem: wake queued readers when writer blocks on active read lock") Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/rwsem-const.h b/arch/sparc/include/asm/rwsem-const.h index a303c9d..e4c61a1 100644 --- a/arch/sparc/include/asm/rwsem-const.h +++ b/arch/sparc/include/asm/rwsem-const.h @@ -5,7 +5,7 @@ #define RWSEM_UNLOCKED_VALUE 0x00000000 #define RWSEM_ACTIVE_BIAS 0x00000001 #define RWSEM_ACTIVE_MASK 0x0000ffff -#define RWSEM_WAITING_BIAS 0xffff0000 +#define RWSEM_WAITING_BIAS (-0x00010000) #define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS #define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) -- cgit v0.10.2 From 86fa04b8742ac681d470786f55e2403ada0075b2 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 17 Aug 2010 17:12:04 -0700 Subject: sparc64: Fix atomic64_t routine return values. Should return 'long' instead of 'int'. Thanks to Dimitris Michailidis and Tony Luck. Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/atomic_64.h b/arch/sparc/include/asm/atomic_64.h index 2050ca0..f0c7422 100644 --- a/arch/sparc/include/asm/atomic_64.h +++ b/arch/sparc/include/asm/atomic_64.h @@ -25,9 +25,9 @@ extern void atomic_sub(int, atomic_t *); extern void atomic64_sub(int, atomic64_t *); extern int atomic_add_ret(int, atomic_t *); -extern int atomic64_add_ret(int, atomic64_t *); +extern long atomic64_add_ret(int, atomic64_t *); extern int atomic_sub_ret(int, atomic_t *); -extern int atomic64_sub_ret(int, atomic64_t *); +extern long atomic64_sub_ret(int, atomic64_t *); #define atomic_dec_return(v) atomic_sub_ret(1, v) #define atomic64_dec_return(v) atomic64_sub_ret(1, v) @@ -91,7 +91,7 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u) ((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n))) #define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) -static inline int atomic64_add_unless(atomic64_t *v, long a, long u) +static inline long atomic64_add_unless(atomic64_t *v, long a, long u) { long c, old; c = atomic64_read(v); -- cgit v0.10.2 From e5093aec2e6b60c3df2420057ffab9ed4a6d2792 Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Wed, 11 Aug 2010 02:02:10 +0000 Subject: net: Fix a memmove bug in dev_gro_receive() >Xin Xiaohui wrote: > I looked into the code dev_gro_receive(), found the code here: > if the frags[0] is pulled to 0, then the page will be released, > and memmove() frags left. > Is that right? I'm not sure if memmove do right or not, but > frags[0].size is never set after memove at least. what I think > a simple way is not to do anything if we found frags[0].size == 0. > The patch is as followed. ... This version of the patch fixes the bug directly in memmove. Reported-by: "Xin, Xiaohui" Signed-off-by: Jarek Poplawski Signed-off-by: David S. Miller diff --git a/net/core/dev.c b/net/core/dev.c index 1ae6543..3721fbb 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3143,7 +3143,7 @@ pull: put_page(skb_shinfo(skb)->frags[0].page); memmove(skb_shinfo(skb)->frags, skb_shinfo(skb)->frags + 1, - --skb_shinfo(skb)->nr_frags); + --skb_shinfo(skb)->nr_frags * sizeof(skb_frag_t)); } } -- cgit v0.10.2 From d7627467b7a8dd6944885290a03a07ceb28c10eb Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 17 Aug 2010 23:52:56 +0100 Subject: Make do_execve() take a const filename pointer Make do_execve() take a const filename pointer so that kernel_execve() compiles correctly on ARM: arch/arm/kernel/sys_arm.c:88: warning: passing argument 1 of 'do_execve' discards qualifiers from pointer target type This also requires the argv and envp arguments to be consted twice, once for the pointer array and once for the strings the array points to. This is because do_execve() passes a pointer to the filename (now const) to copy_strings_kernel(). A simpler alternative would be to cast the filename pointer in do_execve() when it's passed to copy_strings_kernel(). do_execve() may not change any of the strings it is passed as part of the argv or envp lists as they are some of them in .rodata, so marking these strings as const should be fine. Further kernel_execve() and sys_execve() need to be changed to match. This has been test built on x86_64, frv, arm and mips. Signed-off-by: David Howells Tested-by: Ralf Baechle Acked-by: Russell King Signed-off-by: Linus Torvalds diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 88e608a..842dba3 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -387,8 +387,9 @@ EXPORT_SYMBOL(dump_elf_task_fp); * sys_execve() executes a new program. */ asmlinkage int -do_sys_execve(const char __user *ufilename, char __user * __user *argv, - char __user * __user *envp, struct pt_regs *regs) +do_sys_execve(const char __user *ufilename, + const char __user *const __user *argv, + const char __user *const __user *envp, struct pt_regs *regs) { int error; char *filename; diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c index 5b7c541..62e7c61 100644 --- a/arch/arm/kernel/sys_arm.c +++ b/arch/arm/kernel/sys_arm.c @@ -62,8 +62,9 @@ asmlinkage int sys_vfork(struct pt_regs *regs) /* sys_execve() executes a new program. * This is called indirectly via a small wrapper */ -asmlinkage int sys_execve(const char __user *filenamei, char __user * __user *argv, - char __user * __user *envp, struct pt_regs *regs) +asmlinkage int sys_execve(const char __user *filenamei, + const char __user *const __user *argv, + const char __user *const __user *envp, struct pt_regs *regs) { int error; char * filename; @@ -78,14 +79,17 @@ out: return error; } -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { struct pt_regs regs; int ret; memset(®s, 0, sizeof(struct pt_regs)); - ret = do_execve(filename, (char __user * __user *)argv, - (char __user * __user *)envp, ®s); + ret = do_execve(filename, + (const char __user *const __user *)argv, + (const char __user *const __user *)envp, ®s); if (ret < 0) goto out; diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c index e5daddf..9c46aaa 100644 --- a/arch/avr32/kernel/process.c +++ b/arch/avr32/kernel/process.c @@ -384,8 +384,9 @@ asmlinkage int sys_vfork(struct pt_regs *regs) } asmlinkage int sys_execve(const char __user *ufilename, - char __user *__user *uargv, - char __user *__user *uenvp, struct pt_regs *regs) + const char __user *const __user *uargv, + const char __user *const __user *uenvp, + struct pt_regs *regs) { int error; char *filename; diff --git a/arch/avr32/kernel/sys_avr32.c b/arch/avr32/kernel/sys_avr32.c index 459349b..62635a0 100644 --- a/arch/avr32/kernel/sys_avr32.c +++ b/arch/avr32/kernel/sys_avr32.c @@ -7,7 +7,9 @@ */ #include -int kernel_execve(const char *file, char **argv, char **envp) +int kernel_execve(const char *file, + const char *const *argv, + const char *const *envp) { register long scno asm("r8") = __NR_execve; register long sc1 asm("r12") = (long)file; diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c index a566f61..01f98cb 100644 --- a/arch/blackfin/kernel/process.c +++ b/arch/blackfin/kernel/process.c @@ -209,7 +209,9 @@ copy_thread(unsigned long clone_flags, /* * sys_execve() executes a new program. */ -asmlinkage int sys_execve(const char __user *name, char __user * __user *argv, char __user * __user *envp) +asmlinkage int sys_execve(const char __user *name, + const char __user *const __user *argv, + const char __user *const __user *envp) { int error; char *filename; diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c index 93f0f64..9a57db6 100644 --- a/arch/cris/arch-v10/kernel/process.c +++ b/arch/cris/arch-v10/kernel/process.c @@ -204,7 +204,9 @@ asmlinkage int sys_vfork(long r10, long r11, long r12, long r13, long mof, long /* * sys_execve() executes a new program. */ -asmlinkage int sys_execve(const char *fname, char **argv, char **envp, +asmlinkage int sys_execve(const char *fname, + const char *const *argv, + const char *const *envp, long r13, long mof, long srp, struct pt_regs *regs) { diff --git a/arch/cris/arch-v32/kernel/process.c b/arch/cris/arch-v32/kernel/process.c index 2661a95..562f847 100644 --- a/arch/cris/arch-v32/kernel/process.c +++ b/arch/cris/arch-v32/kernel/process.c @@ -218,8 +218,10 @@ sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp, /* sys_execve() executes a new program. */ asmlinkage int -sys_execve(const char *fname, char **argv, char **envp, long r13, long mof, long srp, - struct pt_regs *regs) +sys_execve(const char *fname, + const char *const *argv, + const char *const *envp, long r13, long mof, long srp, + struct pt_regs *regs) { int error; char *filename; diff --git a/arch/frv/kernel/process.c b/arch/frv/kernel/process.c index 428931c..2b63b01 100644 --- a/arch/frv/kernel/process.c +++ b/arch/frv/kernel/process.c @@ -250,8 +250,9 @@ int copy_thread(unsigned long clone_flags, /* * sys_execve() executes a new program. */ -asmlinkage int sys_execve(const char __user *name, char __user * __user *argv, - char __user * __user *envp) +asmlinkage int sys_execve(const char __user *name, + const char __user *const __user *argv, + const char __user *const __user *envp) { int error; char * filename; diff --git a/arch/h8300/kernel/process.c b/arch/h8300/kernel/process.c index 8b7b78d..9747813 100644 --- a/arch/h8300/kernel/process.c +++ b/arch/h8300/kernel/process.c @@ -212,7 +212,10 @@ int copy_thread(unsigned long clone_flags, /* * sys_execve() executes a new program. */ -asmlinkage int sys_execve(const char *name, char **argv, char **envp,int dummy,...) +asmlinkage int sys_execve(const char *name, + const char *const *argv, + const char *const *envp, + int dummy, ...) { int error; char * filename; diff --git a/arch/h8300/kernel/sys_h8300.c b/arch/h8300/kernel/sys_h8300.c index f9b3f44..dc1ac02 100644 --- a/arch/h8300/kernel/sys_h8300.c +++ b/arch/h8300/kernel/sys_h8300.c @@ -51,7 +51,9 @@ asmlinkage void syscall_print(void *dummy,...) * Do a system call from kernel instead of calling sys_execve so we * end up with proper pt_regs. */ -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { register long res __asm__("er0"); register char *const *_c __asm__("er3") = envp; diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index a879c03..16f1c7b 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -633,7 +633,9 @@ dump_fpu (struct pt_regs *pt, elf_fpregset_t dst) } long -sys_execve (const char __user *filename, char __user * __user *argv, char __user * __user *envp, +sys_execve (const char __user *filename, + const char __user *const __user *argv, + const char __user *const __user *envp, struct pt_regs *regs) { char *fname; diff --git a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c index 8665a4d..422bea9 100644 --- a/arch/m32r/kernel/process.c +++ b/arch/m32r/kernel/process.c @@ -289,8 +289,8 @@ asmlinkage int sys_vfork(unsigned long r0, unsigned long r1, unsigned long r2, * sys_execve() executes a new program. */ asmlinkage int sys_execve(const char __user *ufilename, - char __user * __user *uargv, - char __user * __user *uenvp, + const char __user *const __user *uargv, + const char __user *const __user *uenvp, unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, struct pt_regs regs) { diff --git a/arch/m32r/kernel/sys_m32r.c b/arch/m32r/kernel/sys_m32r.c index 0a00f46..d841fb6 100644 --- a/arch/m32r/kernel/sys_m32r.c +++ b/arch/m32r/kernel/sys_m32r.c @@ -93,7 +93,9 @@ asmlinkage int sys_cachectl(char *addr, int nbytes, int op) * Do a system call from kernel instead of calling sys_execve so we * end up with proper pt_regs. */ -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { register long __scno __asm__ ("r7") = __NR_execve; register long __arg3 __asm__ ("r2") = (long)(envp); diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index 221d0b7..18732ab 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -315,7 +315,9 @@ EXPORT_SYMBOL(dump_fpu); /* * sys_execve() executes a new program. */ -asmlinkage int sys_execve(const char __user *name, char __user * __user *argv, char __user * __user *envp) +asmlinkage int sys_execve(const char __user *name, + const char __user *const __user *argv, + const char __user *const __user *envp) { int error; char * filename; diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c index 7789669..2f431ec 100644 --- a/arch/m68k/kernel/sys_m68k.c +++ b/arch/m68k/kernel/sys_m68k.c @@ -459,7 +459,9 @@ asmlinkage int sys_getpagesize(void) * Do a system call from kernel instead of calling sys_execve so we * end up with proper pt_regs. */ -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { register long __res asm ("%d0") = __NR_execve; register long __a asm ("%d1") = (long)(filename); diff --git a/arch/m68knommu/kernel/process.c b/arch/m68knommu/kernel/process.c index 6350f68..4d090d3 100644 --- a/arch/m68knommu/kernel/process.c +++ b/arch/m68knommu/kernel/process.c @@ -350,7 +350,9 @@ void dump(struct pt_regs *fp) /* * sys_execve() executes a new program. */ -asmlinkage int sys_execve(const char *name, char **argv, char **envp) +asmlinkage int sys_execve(const char *name, + const char *const *argv, + const char *const *envp) { int error; char * filename; diff --git a/arch/m68knommu/kernel/sys_m68k.c b/arch/m68knommu/kernel/sys_m68k.c index d65e9c4..68488ae 100644 --- a/arch/m68knommu/kernel/sys_m68k.c +++ b/arch/m68knommu/kernel/sys_m68k.c @@ -44,7 +44,9 @@ asmlinkage int sys_getpagesize(void) * Do a system call from kernel instead of calling sys_execve so we * end up with proper pt_regs. */ -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { register long __res asm ("%d0") = __NR_execve; register long __a asm ("%d1") = (long)(filename); diff --git a/arch/microblaze/kernel/sys_microblaze.c b/arch/microblaze/kernel/sys_microblaze.c index 6abab6e..2250fe9 100644 --- a/arch/microblaze/kernel/sys_microblaze.c +++ b/arch/microblaze/kernel/sys_microblaze.c @@ -47,8 +47,10 @@ asmlinkage long microblaze_clone(int flags, unsigned long stack, struct pt_regs return do_fork(flags, stack, regs, 0, NULL, NULL); } -asmlinkage long microblaze_execve(const char __user *filenamei, char __user *__user *argv, - char __user *__user *envp, struct pt_regs *regs) +asmlinkage long microblaze_execve(const char __user *filenamei, + const char __user *const __user *argv, + const char __user *const __user *envp, + struct pt_regs *regs) { int error; char *filename; @@ -77,7 +79,9 @@ asmlinkage long sys_mmap(unsigned long addr, unsigned long len, * Do a system call from kernel instead of calling sys_execve so we * end up with proper pt_regs. */ -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { register const char *__a __asm__("r5") = filename; register const void *__b __asm__("r6") = argv; diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index bddce0b..1dc6edf 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -258,8 +258,10 @@ asmlinkage int sys_execve(nabi_no_regargs struct pt_regs regs) error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = do_execve(filename, (char __user *__user *) (long)regs.regs[5], - (char __user *__user *) (long)regs.regs[6], ®s); + error = do_execve(filename, + (const char __user *const __user *) (long)regs.regs[5], + (const char __user *const __user *) (long)regs.regs[6], + ®s); putname(filename); out: @@ -436,7 +438,9 @@ asmlinkage void bad_stack(void) * Do a system call from kernel instead of calling sys_execve so we * end up with proper pt_regs. */ -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { register unsigned long __a0 asm("$4") = (unsigned long) filename; register unsigned long __a1 asm("$5") = (unsigned long) argv; diff --git a/arch/mn10300/kernel/process.c b/arch/mn10300/kernel/process.c index 762eb32..f48373e 100644 --- a/arch/mn10300/kernel/process.c +++ b/arch/mn10300/kernel/process.c @@ -269,8 +269,8 @@ asmlinkage long sys_vfork(void) } asmlinkage long sys_execve(const char __user *name, - char __user * __user *argv, - char __user * __user *envp) + const char __user *const __user *argv, + const char __user *const __user *envp) { char *filename; int error; diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c index 1444875..0dc8543 100644 --- a/arch/parisc/hpux/fs.c +++ b/arch/parisc/hpux/fs.c @@ -41,8 +41,10 @@ int hpux_execve(struct pt_regs *regs) if (IS_ERR(filename)) goto out; - error = do_execve(filename, (char __user * __user *) regs->gr[25], - (char __user * __user *) regs->gr[24], regs); + error = do_execve(filename, + (const char __user *const __user *) regs->gr[25], + (const char __user *const __user *) regs->gr[24], + regs); putname(filename); diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index 76332da..4b4b918 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -348,17 +348,22 @@ asmlinkage int sys_execve(struct pt_regs *regs) error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = do_execve(filename, (char __user * __user *) regs->gr[25], - (char __user * __user *) regs->gr[24], regs); + error = do_execve(filename, + (const char __user *const __user *) regs->gr[25], + (const char __user *const __user *) regs->gr[24], + regs); putname(filename); out: return error; } -extern int __execve(const char *filename, char *const argv[], - char *const envp[], struct task_struct *task); -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +extern int __execve(const char *filename, + const char *const argv[], + const char *const envp[], struct task_struct *task); +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { return __execve(filename, argv, envp, current); } diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index feacfb7..91356ff 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -1034,8 +1034,9 @@ int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, flush_fp_to_thread(current); flush_altivec_to_thread(current); flush_spe_to_thread(current); - error = do_execve(filename, (char __user * __user *) a1, - (char __user * __user *) a2, regs); + error = do_execve(filename, + (const char __user *const __user *) a1, + (const char __user *const __user *) a2, regs); putname(filename); out: return error; diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 7eafaf2..d3a2d1c 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -267,8 +267,9 @@ asmlinkage void execve_tail(void) /* * sys_execve() executes a new program. */ -SYSCALL_DEFINE3(execve, const char __user *, name, char __user * __user *, argv, - char __user * __user *, envp) +SYSCALL_DEFINE3(execve, const char __user *, name, + const char __user *const __user *, argv, + const char __user *const __user *, envp) { struct pt_regs *regs = task_pt_regs(current); char *filename; diff --git a/arch/score/kernel/sys_score.c b/arch/score/kernel/sys_score.c index 651096f..e478bf9 100644 --- a/arch/score/kernel/sys_score.c +++ b/arch/score/kernel/sys_score.c @@ -99,8 +99,10 @@ score_execve(struct pt_regs *regs) if (IS_ERR(filename)) return error; - error = do_execve(filename, (char __user *__user*)regs->regs[5], - (char __user *__user *) regs->regs[6], regs); + error = do_execve(filename, + (const char __user *const __user *)regs->regs[5], + (const char __user *const __user *)regs->regs[6], + regs); putname(filename); return error; @@ -110,7 +112,9 @@ score_execve(struct pt_regs *regs) * Do a system call from kernel instead of calling sys_execve so we * end up with proper pt_regs. */ -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { register unsigned long __r4 asm("r4") = (unsigned long) filename; register unsigned long __r5 asm("r5") = (unsigned long) argv; diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index 0529819..762a139 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c @@ -296,9 +296,10 @@ asmlinkage int sys_vfork(unsigned long r4, unsigned long r5, /* * sys_execve() executes a new program. */ -asmlinkage int sys_execve(char __user *ufilename, char __user * __user *uargv, - char __user * __user *uenvp, unsigned long r7, - struct pt_regs __regs) +asmlinkage int sys_execve(const char __user *ufilename, + const char __user *const __user *uargv, + const char __user *const __user *uenvp, + unsigned long r7, struct pt_regs __regs) { struct pt_regs *regs = RELOC_HIDE(&__regs, 0); int error; diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c index 68d128d..210c1ca 100644 --- a/arch/sh/kernel/process_64.c +++ b/arch/sh/kernel/process_64.c @@ -497,8 +497,8 @@ asmlinkage int sys_execve(const char *ufilename, char **uargv, goto out; error = do_execve(filename, - (char __user * __user *)uargv, - (char __user * __user *)uenvp, + (const char __user *const __user *)uargv, + (const char __user *const __user *)uenvp, pregs); putname(filename); out: diff --git a/arch/sh/kernel/sys_sh32.c b/arch/sh/kernel/sys_sh32.c index eb68bfd..f56b6fe5 100644 --- a/arch/sh/kernel/sys_sh32.c +++ b/arch/sh/kernel/sys_sh32.c @@ -71,7 +71,9 @@ asmlinkage int sys_fadvise64_64_wrapper(int fd, u32 offset0, u32 offset1, * Do a system call from kernel instead of calling sys_execve so we * end up with proper pt_regs. */ -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { register long __sc0 __asm__ ("r3") = __NR_execve; register long __sc4 __asm__ ("r4") = (long) filename; diff --git a/arch/sh/kernel/sys_sh64.c b/arch/sh/kernel/sys_sh64.c index 2872357..c5a38c4 100644 --- a/arch/sh/kernel/sys_sh64.c +++ b/arch/sh/kernel/sys_sh64.c @@ -33,7 +33,9 @@ * Do a system call from kernel instead of calling sys_execve so we * end up with proper pt_regs. */ -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { register unsigned long __sc0 __asm__ ("r9") = ((0x13 << 16) | __NR_execve); register unsigned long __sc2 __asm__ ("r2") = (unsigned long) filename; diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c index 40e29fc..1752929 100644 --- a/arch/sparc/kernel/process_32.c +++ b/arch/sparc/kernel/process_32.c @@ -633,8 +633,10 @@ asmlinkage int sparc_execve(struct pt_regs *regs) if(IS_ERR(filename)) goto out; error = do_execve(filename, - (char __user * __user *)regs->u_regs[base + UREG_I1], - (char __user * __user *)regs->u_regs[base + UREG_I2], + (const char __user *const __user *) + regs->u_regs[base + UREG_I1], + (const char __user *const __user *) + regs->u_regs[base + UREG_I2], regs); putname(filename); out: diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c index dbe81a3..485f547 100644 --- a/arch/sparc/kernel/process_64.c +++ b/arch/sparc/kernel/process_64.c @@ -739,9 +739,9 @@ asmlinkage int sparc_execve(struct pt_regs *regs) if (IS_ERR(filename)) goto out; error = do_execve(filename, - (char __user * __user *) + (const char __user *const __user *) regs->u_regs[base + UREG_I1], - (char __user * __user *) + (const char __user *const __user *) regs->u_regs[base + UREG_I2], regs); putname(filename); if (!error) { diff --git a/arch/sparc/kernel/sys_sparc_32.c b/arch/sparc/kernel/sys_sparc_32.c index ee995b7..5079413 100644 --- a/arch/sparc/kernel/sys_sparc_32.c +++ b/arch/sparc/kernel/sys_sparc_32.c @@ -282,7 +282,9 @@ out: * Do a system call from kernel instead of calling sys_execve so we * end up with proper pt_regs. */ -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { long __res; register long __g1 __asm__ ("g1") = __NR_execve; diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c index 3d435c4..f836f4e 100644 --- a/arch/sparc/kernel/sys_sparc_64.c +++ b/arch/sparc/kernel/sys_sparc_64.c @@ -758,7 +758,9 @@ SYSCALL_DEFINE5(rt_sigaction, int, sig, const struct sigaction __user *, act, * Do a system call from kernel instead of calling sys_execve so we * end up with proper pt_regs. */ -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { long __res; register long __g1 __asm__ ("g1") = __NR_execve; diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c index ed590ad..985cc28 100644 --- a/arch/tile/kernel/process.c +++ b/arch/tile/kernel/process.c @@ -543,8 +543,9 @@ long _sys_vfork(struct pt_regs *regs) /* * sys_execve() executes a new program. */ -long _sys_execve(char __user *path, char __user *__user *argv, - char __user *__user *envp, struct pt_regs *regs) +long _sys_execve(const char __user *path, + const char __user *const __user *argv, + const char __user *const __user *envp, struct pt_regs *regs) { long error; char *filename; diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c index 59b20d9..cd145ed 100644 --- a/arch/um/kernel/exec.c +++ b/arch/um/kernel/exec.c @@ -44,8 +44,9 @@ void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp) PT_REGS_SP(regs) = esp; } -static long execve1(const char *file, char __user * __user *argv, - char __user *__user *env) +static long execve1(const char *file, + const char __user *const __user *argv, + const char __user *const __user *env) { long error; diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c index 7427c0b..5ddb246 100644 --- a/arch/um/kernel/syscall.c +++ b/arch/um/kernel/syscall.c @@ -51,7 +51,9 @@ long old_mmap(unsigned long addr, unsigned long len, return err; } -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { mm_segment_t fs; int ret; diff --git a/arch/x86/include/asm/syscalls.h b/arch/x86/include/asm/syscalls.h index feb2ff9..f1d8b44 100644 --- a/arch/x86/include/asm/syscalls.h +++ b/arch/x86/include/asm/syscalls.h @@ -23,8 +23,9 @@ long sys_iopl(unsigned int, struct pt_regs *); /* kernel/process.c */ int sys_fork(struct pt_regs *); int sys_vfork(struct pt_regs *); -long sys_execve(const char __user *, char __user * __user *, - char __user * __user *, struct pt_regs *); +long sys_execve(const char __user *, + const char __user *const __user *, + const char __user *const __user *, struct pt_regs *); long sys_clone(unsigned long, unsigned long, void __user *, void __user *, struct pt_regs *); diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 64ecaf0..57d1868 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -301,8 +301,9 @@ EXPORT_SYMBOL(kernel_thread); /* * sys_execve() executes a new program. */ -long sys_execve(const char __user *name, char __user * __user *argv, - char __user * __user *envp, struct pt_regs *regs) +long sys_execve(const char __user *name, + const char __user *const __user *argv, + const char __user *const __user *envp, struct pt_regs *regs) { long error; char *filename; diff --git a/arch/x86/kernel/sys_i386_32.c b/arch/x86/kernel/sys_i386_32.c index 196552b..d5e0662 100644 --- a/arch/x86/kernel/sys_i386_32.c +++ b/arch/x86/kernel/sys_i386_32.c @@ -28,7 +28,9 @@ * Do a system call from kernel instead of calling sys_execve so we * end up with proper pt_regs. */ -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { long __res; asm volatile ("push %%ebx ; movl %2,%%ebx ; int $0x80 ; pop %%ebx" diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c index 7c2f38f..e3558b9 100644 --- a/arch/xtensa/kernel/process.c +++ b/arch/xtensa/kernel/process.c @@ -318,8 +318,9 @@ long xtensa_clone(unsigned long clone_flags, unsigned long newsp, */ asmlinkage -long xtensa_execve(const char __user *name, char __user * __user *argv, - char __user * __user *envp, +long xtensa_execve(const char __user *name, + const char __user *const __user *argv, + const char __user *const __user *envp, long a3, long a4, long a5, struct pt_regs *regs) { diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 9e60fd2..a7528b9 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -108,7 +108,7 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) Node *fmt; struct file * interp_file = NULL; char iname[BINPRM_BUF_SIZE]; - char *iname_addr = iname; + const char *iname_addr = iname; int retval; int fd_binary = -1; diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c index aca9d55..396a988 100644 --- a/fs/binfmt_script.c +++ b/fs/binfmt_script.c @@ -16,7 +16,8 @@ static int load_script(struct linux_binprm *bprm,struct pt_regs *regs) { - char *cp, *i_name, *i_arg; + const char *i_arg, *i_name; + char *cp; struct file *file; char interp[BINPRM_BUF_SIZE]; int retval; diff --git a/fs/exec.c b/fs/exec.c index 7761837..05c7d6b 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -361,13 +361,13 @@ err: /* * count() counts the number of strings in array ARGV. */ -static int count(char __user * __user * argv, int max) +static int count(const char __user * const __user * argv, int max) { int i = 0; if (argv != NULL) { for (;;) { - char __user * p; + const char __user * p; if (get_user(p, argv)) return -EFAULT; @@ -387,7 +387,7 @@ static int count(char __user * __user * argv, int max) * processes's memory to the new process's stack. The call to get_user_pages() * ensures the destination page is created and not swapped out. */ -static int copy_strings(int argc, char __user * __user * argv, +static int copy_strings(int argc, const char __user *const __user *argv, struct linux_binprm *bprm) { struct page *kmapped_page = NULL; @@ -396,7 +396,7 @@ static int copy_strings(int argc, char __user * __user * argv, int ret; while (argc-- > 0) { - char __user *str; + const char __user *str; int len; unsigned long pos; @@ -470,12 +470,13 @@ out: /* * Like copy_strings, but get argv and its values from kernel memory. */ -int copy_strings_kernel(int argc,char ** argv, struct linux_binprm *bprm) +int copy_strings_kernel(int argc, const char *const *argv, + struct linux_binprm *bprm) { int r; mm_segment_t oldfs = get_fs(); set_fs(KERNEL_DS); - r = copy_strings(argc, (char __user * __user *)argv, bprm); + r = copy_strings(argc, (const char __user *const __user *)argv, bprm); set_fs(oldfs); return r; } @@ -997,7 +998,7 @@ EXPORT_SYMBOL(flush_old_exec); void setup_new_exec(struct linux_binprm * bprm) { int i, ch; - char * name; + const char *name; char tcomm[sizeof(current->comm)]; arch_pick_mmap_layout(current->mm); @@ -1316,9 +1317,9 @@ EXPORT_SYMBOL(search_binary_handler); /* * sys_execve() executes a new program. */ -int do_execve(char * filename, - char __user *__user *argv, - char __user *__user *envp, +int do_execve(const char * filename, + const char __user *const __user *argv, + const char __user *const __user *envp, struct pt_regs * regs) { struct linux_binprm *bprm; diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index c809e28..a065612 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -50,8 +50,8 @@ struct linux_binprm{ int unsafe; /* how unsafe this exec is (mask of LSM_UNSAFE_*) */ unsigned int per_clear; /* bits to clear in current->personality */ int argc, envc; - char * filename; /* Name of binary as seen by procps */ - char * interp; /* Name of the binary really executed. Most + const char * filename; /* Name of binary as seen by procps */ + const char * interp; /* Name of the binary really executed. Most of the time same as filename, but could be different for binfmt_{misc,script} */ unsigned interp_flags; @@ -126,7 +126,8 @@ extern int setup_arg_pages(struct linux_binprm * bprm, unsigned long stack_top, int executable_stack); extern int bprm_mm_init(struct linux_binprm *bprm); -extern int copy_strings_kernel(int argc,char ** argv,struct linux_binprm *bprm); +extern int copy_strings_kernel(int argc, const char *const *argv, + struct linux_binprm *bprm); extern int prepare_bprm_creds(struct linux_binprm *bprm); extern void install_exec_creds(struct linux_binprm *bprm); extern void do_coredump(long signr, int exit_code, struct pt_regs *regs); diff --git a/include/linux/sched.h b/include/linux/sched.h index ce160d6..1e2a6db 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2109,7 +2109,9 @@ extern void daemonize(const char *, ...); extern int allow_signal(int); extern int disallow_signal(int); -extern int do_execve(char *, char __user * __user *, char __user * __user *, struct pt_regs *); +extern int do_execve(const char *, + const char __user * const __user *, + const char __user * const __user *, struct pt_regs *); extern long do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long, int __user *, int __user *); struct task_struct *fork_idle(int); diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 6e5d197..e6319d1 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -820,7 +820,7 @@ asmlinkage long sys_fanotify_mark(int fanotify_fd, unsigned int flags, u64 mask, int fd, const char __user *pathname); -int kernel_execve(const char *filename, char *const argv[], char *const envp[]); +int kernel_execve(const char *filename, const char *const argv[], const char *const envp[]); asmlinkage long sys_perf_event_open( diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c index 2b10853..3098a38 100644 --- a/init/do_mounts_initrd.c +++ b/init/do_mounts_initrd.c @@ -24,10 +24,11 @@ static int __init no_initrd(char *str) __setup("noinitrd", no_initrd); -static int __init do_linuxrc(void * shell) +static int __init do_linuxrc(void *_shell) { - static char *argv[] = { "linuxrc", NULL, }; - extern char * envp_init[]; + static const char *argv[] = { "linuxrc", NULL, }; + extern const char *envp_init[]; + const char *shell = _shell; sys_close(old_fd);sys_close(root_fd); sys_setsid(); diff --git a/init/main.c b/init/main.c index 22d61cb..94ab488 100644 --- a/init/main.c +++ b/init/main.c @@ -197,8 +197,8 @@ static int __init set_reset_devices(char *str) __setup("reset_devices", set_reset_devices); -static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, }; -char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, }; +static const char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, }; +const char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, }; static const char *panic_later, *panic_param; extern const struct obs_kernel_param __setup_start[], __setup_end[]; @@ -809,7 +809,7 @@ static void __init do_pre_smp_initcalls(void) do_one_initcall(*fn); } -static void run_init_process(char *init_filename) +static void run_init_process(const char *init_filename) { argv_init[0] = init_filename; kernel_execve(init_filename, argv_init, envp_init); diff --git a/kernel/kmod.c b/kernel/kmod.c index 6e9b196..9cd0591 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -153,7 +153,9 @@ static int ____call_usermodehelper(void *data) goto fail; } - retval = kernel_execve(sub_info->path, sub_info->argv, sub_info->envp); + retval = kernel_execve(sub_info->path, + (const char *const *)sub_info->argv, + (const char *const *)sub_info->envp); /* Exec failed? */ fail: diff --git a/security/commoncap.c b/security/commoncap.c index 4e01599..9d172e6 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -40,7 +40,7 @@ * * Warn if that happens, once per boot. */ -static void warn_setuid_and_fcaps_mixed(char *fname) +static void warn_setuid_and_fcaps_mixed(const char *fname) { static int warned; if (!warned) { -- cgit v0.10.2 From f362b73244fb16ea4ae127ced1467dd8adaa7733 Mon Sep 17 00:00:00 2001 From: Daniel J Blueman Date: Tue, 17 Aug 2010 23:56:55 +0100 Subject: Fix unprotected access to task credentials in waitid() Using a program like the following: #include #include #include #include int main() { id_t id; siginfo_t infop; pid_t res; id = fork(); if (id == 0) { sleep(1); exit(0); } kill(id, SIGSTOP); alarm(1); waitid(P_PID, id, &infop, WCONTINUED); return 0; } to call waitid() on a stopped process results in access to the child task's credentials without the RCU read lock being held - which may be replaced in the meantime - eliciting the following warning: =================================================== [ INFO: suspicious rcu_dereference_check() usage. ] --------------------------------------------------- kernel/exit.c:1460 invoked rcu_dereference_check() without protection! other info that might help us debug this: rcu_scheduler_active = 1, debug_locks = 1 2 locks held by waitid02/22252: #0: (tasklist_lock){.?.?..}, at: [] do_wait+0xc5/0x310 #1: (&(&sighand->siglock)->rlock){-.-...}, at: [] wait_consider_task+0x19a/0xbe0 stack backtrace: Pid: 22252, comm: waitid02 Not tainted 2.6.35-323cd+ #3 Call Trace: [] lockdep_rcu_dereference+0xa4/0xc0 [] wait_consider_task+0xaf1/0xbe0 [] do_wait+0xf5/0x310 [] sys_waitid+0x86/0x1f0 [] ? child_wait_callback+0x0/0x70 [] system_call_fastpath+0x16/0x1b This is fixed by holding the RCU read lock in wait_task_continued() to ensure that the task's current credentials aren't destroyed between us reading the cred pointer and us reading the UID from those credentials. Furthermore, protect wait_task_stopped() in the same way. We don't need to keep holding the RCU read lock once we've read the UID from the credentials as holding the RCU read lock doesn't stop the target task from changing its creds under us - so the credentials may be outdated immediately after we've read the pointer, lock or no lock. Signed-off-by: Daniel J Blueman Signed-off-by: David Howells Acked-by: Paul E. McKenney Acked-by: Oleg Nesterov Signed-off-by: Linus Torvalds diff --git a/kernel/exit.c b/kernel/exit.c index 671ed56..0312022 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -1386,8 +1386,7 @@ static int wait_task_stopped(struct wait_opts *wo, if (!unlikely(wo->wo_flags & WNOWAIT)) *p_code = 0; - /* don't need the RCU readlock here as we're holding a spinlock */ - uid = __task_cred(p)->uid; + uid = task_uid(p); unlock_sig: spin_unlock_irq(&p->sighand->siglock); if (!exit_code) @@ -1460,7 +1459,7 @@ static int wait_task_continued(struct wait_opts *wo, struct task_struct *p) } if (!unlikely(wo->wo_flags & WNOWAIT)) p->signal->flags &= ~SIGNAL_STOP_CONTINUED; - uid = __task_cred(p)->uid; + uid = task_uid(p); spin_unlock_irq(&p->sighand->siglock); pid = task_pid_vnr(p); -- cgit v0.10.2 From a7c8962bfbc730a9acc0a635bad0f9628b6e816a Mon Sep 17 00:00:00 2001 From: David Miller Date: Mon, 16 Aug 2010 21:20:07 -0700 Subject: arcmsr_hba: Missing slab.h include Signed-off-by: David S. Miller Signed-off-by: Linus Torvalds diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 95a895d..c8dc392 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include -- cgit v0.10.2 From 602586a83b719df0fbd94196a1359ed35aeb2df3 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Tue, 17 Aug 2010 15:23:56 -0700 Subject: shmem: put_super must percpu_counter_destroy list_add() corruption messages reported from shmem_fill_super()'s recently introduced percpu_counter_init(): shmem_put_super() needs to remember to percpu_counter_destroy(). And also check error from percpu_counter_init(). Reported-bisected-and-tested-by: Tetsuo Handa Signed-off-by: Hugh Dickins Signed-off-by: Linus Torvalds diff --git a/mm/shmem.c b/mm/shmem.c index dfaa0f4..080b09a 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2325,7 +2325,10 @@ static int shmem_show_options(struct seq_file *seq, struct vfsmount *vfs) static void shmem_put_super(struct super_block *sb) { - kfree(sb->s_fs_info); + struct shmem_sb_info *sbinfo = SHMEM_SB(sb); + + percpu_counter_destroy(&sbinfo->used_blocks); + kfree(sbinfo); sb->s_fs_info = NULL; } @@ -2367,7 +2370,8 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent) #endif spin_lock_init(&sbinfo->stat_lock); - percpu_counter_init(&sbinfo->used_blocks, 0); + if (percpu_counter_init(&sbinfo->used_blocks, 0)) + goto failed; sbinfo->free_inodes = sbinfo->max_inodes; sb->s_maxbytes = SHMEM_MAX_BYTES; -- cgit v0.10.2 From 3a3a5ddb7a0f43c3dd0f98673f3d930a456725f8 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 16 Aug 2010 18:09:31 +1000 Subject: Update recovery_offset even when external metadata is used. The update of ->recovery_offset in sync_sbs is appropriate even then external metadata is in use. However sync_sbs is only called when native metadata is used. So move that update in to the top of md_update_sb (which is the only caller of sync_sbs) before the test on ->external. This moves the update out of ->write_lock protection, but those fields only need ->reconfig_mutex protection which they still have. Also move the test on ->persistent up to where ->external is set as for metadata update purposes they are the same. Clear MD_CHANGE_DEVS and MD_CHANGE_CLEAN as they can only be confusing if ->external is set or ->persistent isn't. Finally move the update of ->utime down as it is only relevent (like the ->events update) for native metadata. Signed-off-by: NeilBrown Reported-by: "Kwolek, Adam" diff --git a/drivers/md/md.c b/drivers/md/md.c index 11567c7..c148b63 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2136,16 +2136,6 @@ static void sync_sbs(mddev_t * mddev, int nospares) * with the rest of the array) */ mdk_rdev_t *rdev; - - /* First make sure individual recovery_offsets are correct */ - list_for_each_entry(rdev, &mddev->disks, same_set) { - if (rdev->raid_disk >= 0 && - mddev->delta_disks >= 0 && - !test_bit(In_sync, &rdev->flags) && - mddev->curr_resync_completed > rdev->recovery_offset) - rdev->recovery_offset = mddev->curr_resync_completed; - - } list_for_each_entry(rdev, &mddev->disks, same_set) { if (rdev->sb_events == mddev->events || (nospares && @@ -2167,12 +2157,27 @@ static void md_update_sb(mddev_t * mddev, int force_change) int sync_req; int nospares = 0; - mddev->utime = get_seconds(); - if (mddev->external) - return; repeat: + /* First make sure individual recovery_offsets are correct */ + list_for_each_entry(rdev, &mddev->disks, same_set) { + if (rdev->raid_disk >= 0 && + mddev->delta_disks >= 0 && + !test_bit(In_sync, &rdev->flags) && + mddev->curr_resync_completed > rdev->recovery_offset) + rdev->recovery_offset = mddev->curr_resync_completed; + + } + if (mddev->external || !mddev->persistent) { + clear_bit(MD_CHANGE_DEVS, &mddev->flags); + clear_bit(MD_CHANGE_CLEAN, &mddev->flags); + wake_up(&mddev->sb_wait); + return; + } + spin_lock_irq(&mddev->write_lock); + mddev->utime = get_seconds(); + set_bit(MD_CHANGE_PENDING, &mddev->flags); if (test_and_clear_bit(MD_CHANGE_DEVS, &mddev->flags)) force_change = 1; @@ -2221,19 +2226,6 @@ repeat: MD_BUG(); mddev->events --; } - - /* - * do not write anything to disk if using - * nonpersistent superblocks - */ - if (!mddev->persistent) { - if (!mddev->external) - clear_bit(MD_CHANGE_PENDING, &mddev->flags); - - spin_unlock_irq(&mddev->write_lock); - wake_up(&mddev->sb_wait); - return; - } sync_sbs(mddev, nospares); spin_unlock_irq(&mddev->write_lock); -- cgit v0.10.2 From e6ffbcb6cd0ac471223df24ae77eb486c1ee68cc Mon Sep 17 00:00:00 2001 From: Adrian Drzewiecki Date: Wed, 18 Aug 2010 11:49:02 +1000 Subject: md: Notify sysfs when RAID1/5/10 disk is In_sync. When RAID1 is done syncing disks, it'll update the state of synced rdevs to In_sync. But it neglected to notify sysfs that the attribute changed. So any programs that are waiting for an rdev's state to change will not be woken. (raid5/raid10 added by neilb) Signed-off-by: Adrian Drzewiecki Signed-off-by: NeilBrown diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 73cc74f..0e1abf1 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1135,6 +1135,7 @@ static int raid1_spare_active(mddev_t *mddev) spin_lock_irqsave(&conf->device_lock, flags); mddev->degraded--; spin_unlock_irqrestore(&conf->device_lock, flags); + sysfs_notify_dirent(rdev->sysfs_state); } } diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index a88aeb5..76d1fc9 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1130,6 +1130,7 @@ static int raid10_spare_active(mddev_t *mddev) spin_lock_irqsave(&conf->device_lock, flags); mddev->degraded--; spin_unlock_irqrestore(&conf->device_lock, flags); + sysfs_notify_dirent(tmp->rdev->sysfs_state); } } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 866d4b5..7865dd0 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5341,6 +5341,7 @@ static int raid5_spare_active(mddev_t *mddev) spin_lock_irqsave(&conf->device_lock, flags); mddev->degraded--; spin_unlock_irqrestore(&conf->device_lock, flags); + sysfs_notify_dirent(tmp->rdev->sysfs_state); } } print_raid5_conf(conf); -- cgit v0.10.2 From 6b9656205469269c050963c71fca1998b247a560 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 18 Aug 2010 11:56:59 +1000 Subject: md: provide appropriate return value for spare_active functions. md_check_recovery expects ->spare_active to return 'true' if any spares were activated, but none of them do, so the consequent change in 'degraded' is not notified through sysfs. So count the number of spares activated, subtract it from 'degraded' just once, and return it. Reported-by: Adrian Drzewiecki Signed-off-by: NeilBrown diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 0e1abf1..64d9652 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1120,6 +1120,8 @@ static int raid1_spare_active(mddev_t *mddev) { int i; conf_t *conf = mddev->private; + int count = 0; + unsigned long flags; /* * Find all failed disks within the RAID1 configuration @@ -1131,16 +1133,16 @@ static int raid1_spare_active(mddev_t *mddev) if (rdev && !test_bit(Faulty, &rdev->flags) && !test_and_set_bit(In_sync, &rdev->flags)) { - unsigned long flags; - spin_lock_irqsave(&conf->device_lock, flags); - mddev->degraded--; - spin_unlock_irqrestore(&conf->device_lock, flags); + count++; sysfs_notify_dirent(rdev->sysfs_state); } } + spin_lock_irqsave(&conf->device_lock, flags); + mddev->degraded -= count; + spin_unlock_irqrestore(&conf->device_lock, flags); print_conf(conf); - return 0; + return count; } diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 76d1fc9..a2f8a71 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1116,6 +1116,8 @@ static int raid10_spare_active(mddev_t *mddev) int i; conf_t *conf = mddev->private; mirror_info_t *tmp; + int count = 0; + unsigned long flags; /* * Find all non-in_sync disks within the RAID10 configuration @@ -1126,16 +1128,16 @@ static int raid10_spare_active(mddev_t *mddev) if (tmp->rdev && !test_bit(Faulty, &tmp->rdev->flags) && !test_and_set_bit(In_sync, &tmp->rdev->flags)) { - unsigned long flags; - spin_lock_irqsave(&conf->device_lock, flags); - mddev->degraded--; - spin_unlock_irqrestore(&conf->device_lock, flags); + count++; sysfs_notify_dirent(tmp->rdev->sysfs_state); } } + spin_lock_irqsave(&conf->device_lock, flags); + mddev->degraded -= count; + spin_unlock_irqrestore(&conf->device_lock, flags); print_conf(conf); - return 0; + return count; } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 7865dd0..69b0a16 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5330,6 +5330,8 @@ static int raid5_spare_active(mddev_t *mddev) int i; raid5_conf_t *conf = mddev->private; struct disk_info *tmp; + int count = 0; + unsigned long flags; for (i = 0; i < conf->raid_disks; i++) { tmp = conf->disks + i; @@ -5337,15 +5339,15 @@ static int raid5_spare_active(mddev_t *mddev) && tmp->rdev->recovery_offset == MaxSector && !test_bit(Faulty, &tmp->rdev->flags) && !test_and_set_bit(In_sync, &tmp->rdev->flags)) { - unsigned long flags; - spin_lock_irqsave(&conf->device_lock, flags); - mddev->degraded--; - spin_unlock_irqrestore(&conf->device_lock, flags); + count++; sysfs_notify_dirent(tmp->rdev->sysfs_state); } } + spin_lock_irqsave(&conf->device_lock, flags); + mddev->degraded -= count; + spin_unlock_irqrestore(&conf->device_lock, flags); print_raid5_conf(conf); - return 0; + return count; } static int raid5_remove_disk(mddev_t *mddev, int number) -- cgit v0.10.2 From dc6ae5e471425762122bb93310dd46101ccd840d Mon Sep 17 00:00:00 2001 From: Jate Sujjavanich Date: Mon, 7 Jun 2010 11:39:30 -0400 Subject: m68knommu: arch/m68k/include/asm/ide.h fix for nommu The arch/m68k/include/asm/ide.h produces errors when the IDE driver is compiled for my 523x uClinux system under kernel. The header makes some redefines of operators not defined in the arch/m68k/include/asm/io_no.h header. There are no separate mmio and iospace defines. Signed-off-by: Jate Sujjavanich Acked-by: Geert Uytterhoeven Signed-off-by: Greg Ungerer diff --git a/arch/m68k/include/asm/ide.h b/arch/m68k/include/asm/ide.h index 3958726..492fee8 100644 --- a/arch/m68k/include/asm/ide.h +++ b/arch/m68k/include/asm/ide.h @@ -1,6 +1,4 @@ /* - * linux/include/asm-m68k/ide.h - * * Copyright (C) 1994-1996 Linus Torvalds & authors */ @@ -34,6 +32,8 @@ #include #include +#ifdef CONFIG_MMU + /* * Get rid of defs from io.h - ide has its private and conflicting versions * Since so far no single m68k platform uses ISA/PCI I/O space for IDE, we @@ -53,5 +53,14 @@ #define __ide_mm_outsw(port, addr, n) raw_outsw((u16 *)port, addr, n) #define __ide_mm_outsl(port, addr, n) raw_outsl((u32 *)port, addr, n) +#else + +#define __ide_mm_insw(port, addr, n) io_insw((unsigned int)port, addr, n) +#define __ide_mm_insl(port, addr, n) io_insl((unsigned int)port, addr, n) +#define __ide_mm_outsw(port, addr, n) io_outsw((unsigned int)port, addr, n) +#define __ide_mm_outsl(port, addr, n) io_outsl((unsigned int)port, addr, n) + +#endif /* CONFIG_MMU */ + #endif /* __KERNEL__ */ #endif /* _M68K_IDE_H */ -- cgit v0.10.2 From c7484cf467df44c0d478b0412dc01e71fbec7923 Mon Sep 17 00:00:00 2001 From: Kulikov Vasiliy Date: Wed, 14 Jul 2010 22:01:13 +0400 Subject: m68knommu: formatting of pointers in printk() arch/m68knommu/kernel/process.c: formatting of pointers in printk() Use %p instead of %08x in printk(). Signed-off-by: Kulikov Vasiliy Signed-off-by: Greg Ungerer diff --git a/arch/m68knommu/kernel/process.c b/arch/m68knommu/kernel/process.c index 6350f68..3fb9e45 100644 --- a/arch/m68knommu/kernel/process.c +++ b/arch/m68knommu/kernel/process.c @@ -316,14 +316,14 @@ void dump(struct pt_regs *fp) fp->d0, fp->d1, fp->d2, fp->d3); printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", fp->d4, fp->d5, fp->a0, fp->a1); - printk(KERN_EMERG "\nUSP: %08x TRAPFRAME: %08x\n", - (unsigned int) rdusp(), (unsigned int) fp); + printk(KERN_EMERG "\nUSP: %08x TRAPFRAME: %p\n", + (unsigned int) rdusp(), fp); printk(KERN_EMERG "\nCODE:"); tp = ((unsigned char *) fp->pc) - 0x20; for (sp = (unsigned long *) tp, i = 0; (i < 0x40); i += 4) { if ((i % 0x10) == 0) - printk(KERN_EMERG "%08x: ", (int) (tp + i)); + printk(KERN_EMERG "%p: ", tp + i); printk("%08x ", (int) *sp++); } printk(KERN_EMERG "\n"); @@ -332,7 +332,7 @@ void dump(struct pt_regs *fp) tp = ((unsigned char *) fp) - 0x40; for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) { if ((i % 0x10) == 0) - printk(KERN_EMERG "%08x: ", (int) (tp + i)); + printk(KERN_EMERG "%p: ", tp + i); printk("%08x ", (int) *sp++); } printk(KERN_EMERG "\n"); @@ -341,7 +341,7 @@ void dump(struct pt_regs *fp) tp = (unsigned char *) (rdusp() - 0x10); for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) { if ((i % 0x10) == 0) - printk(KERN_EMERG "%08x: ", (int) (tp + i)); + printk(KERN_EMERG "%p: ", tp + i); printk("%08x ", (int) *sp++); } printk(KERN_EMERG "\n"); -- cgit v0.10.2 From 5e1c53356d79591b10cdea12e3d5ebace8e7b6fa Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Wed, 28 Jul 2010 13:32:46 +1000 Subject: m68knommu: include sched.h in ColdFire/SPI driver Using the coldfire qspi driver, I get the following error: drivers/spi/coldfire_qspi.c: In function 'mcfqspi_irq_handler': drivers/spi/coldfire_qspi.c:166: error: 'TASK_NORMAL' undeclared (first use in this function) drivers/spi/coldfire_qspi.c:166: error: (Each undeclared identifier is reported only once It is solved by adding the following include to coldfire_sqpi.c: #include Fix suggested by Jate Sujjavanich Signed-off-by: Greg Ungerer diff --git a/drivers/spi/coldfire_qspi.c b/drivers/spi/coldfire_qspi.c index 59be3ef..052b3c7 100644 --- a/drivers/spi/coldfire_qspi.c +++ b/drivers/spi/coldfire_qspi.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include -- cgit v0.10.2 From b10f997bb0f4e5b34d447f498fb85834a40d3acb Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 17 Aug 2010 21:44:13 -0700 Subject: sparc64: Really fix atomic64_t interface types. Linus noticed that some of the interface arguments didn't get "int" --> "long" conversion, as needed. Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/atomic_64.h b/arch/sparc/include/asm/atomic_64.h index f0c7422..bdb2ff8 100644 --- a/arch/sparc/include/asm/atomic_64.h +++ b/arch/sparc/include/asm/atomic_64.h @@ -20,14 +20,14 @@ #define atomic64_set(v, i) (((v)->counter) = i) extern void atomic_add(int, atomic_t *); -extern void atomic64_add(int, atomic64_t *); +extern void atomic64_add(long, atomic64_t *); extern void atomic_sub(int, atomic_t *); -extern void atomic64_sub(int, atomic64_t *); +extern void atomic64_sub(long, atomic64_t *); extern int atomic_add_ret(int, atomic_t *); -extern long atomic64_add_ret(int, atomic64_t *); +extern long atomic64_add_ret(long, atomic64_t *); extern int atomic_sub_ret(int, atomic_t *); -extern long atomic64_sub_ret(int, atomic64_t *); +extern long atomic64_sub_ret(long, atomic64_t *); #define atomic_dec_return(v) atomic_sub_ret(1, v) #define atomic64_dec_return(v) atomic64_sub_ret(1, v) -- cgit v0.10.2 From 5c79a5ae23e72fa12f1c7c528f62bf3ea35da0dc Mon Sep 17 00:00:00 2001 From: Ernst Schwab Date: Mon, 16 Aug 2010 15:10:11 +0200 Subject: spi.h: missing kernel-doc notation, please fix Added comments in kernel-doc notation for previously added struct fields. Signed-off-by: Ernst Schwab Acked-by: Randy Dunlap Signed-off-by: Grant Likely diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index ae0a528..92e52a1 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -213,6 +213,9 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * @dma_alignment: SPI controller constraint on DMA buffers alignment. * @mode_bits: flags understood by this controller driver * @flags: other constraints relevant to this driver + * @bus_lock_spinlock: spinlock for SPI bus locking + * @bus_lock_mutex: mutex for SPI bus locking + * @bus_lock_flag: indicates that the SPI bus is locked for exclusive use * @setup: updates the device mode and clocking records used by a * device's SPI controller; protocol code may call this. This * must fail if an unrecognized or unsupported mode is requested. -- cgit v0.10.2 From f4ae2faa40199b97b12f508234640bc565d166f8 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Wed, 11 Aug 2010 14:07:01 +0300 Subject: fix reiserfs_evict_inode end_writeback second call reiserfs_evict_inode calls end_writeback two times hitting kernel BUG at fs/inode.c:298 becase inode->i_state is I_CLEAR already. Signed-off-by: Sergey Senozhatsky Signed-off-by: Al Viro diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index ae35413..caa7583 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -83,6 +83,7 @@ void reiserfs_evict_inode(struct inode *inode) dquot_drop(inode); inode->i_blocks = 0; reiserfs_write_unlock_once(inode->i_sb, depth); + return; no_delete: end_writeback(inode); -- cgit v0.10.2 From b845ff8f3ea2988ad5041315e2d35298e85cbc2f Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Tue, 17 Aug 2010 17:08:35 +0300 Subject: cramfs: only unlock new inodes Commit 77b8a75f5bb introduced a warning at fs/inode.c:692 unlock_new_inode(), caused by unlock_new_inode() being called on existing inodes as well. This patch changes setup_inode() to only call unlock_new_inode() for I_NEW inodes. Signed-off-by: Alexander Shishkin Signed-off-by: Al Viro diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index a53b130..1e7a330 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -80,7 +80,7 @@ static struct inode *get_cramfs_inode(struct super_block *sb, } } else { inode = iget_locked(sb, CRAMINO(cramfs_inode)); - if (inode) { + if (inode && (inode->i_state & I_NEW)) { setup_inode(inode, cramfs_inode); unlock_new_inode(inode); } -- cgit v0.10.2 From dad5eb6daa7eeb63d4fc9d982892c59faa07e797 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 17 Aug 2010 12:42:13 +0200 Subject: vfs: update ctime when changing the file's permission by setfacl generic_acl_set didn't update the ctime of the file when its permission was changed. Steps to reproduce: # touch aaa # stat -c %Z aaa 1275289822 # setfacl -m 'u::x,g::x,o::x' aaa # stat -c %Z aaa 1275289822 <- unchanged But, according to the spec of the ctime, vfs must update it. Port of ext3 patch by Miao Xie . CC: Al Viro Signed-off-by: Jan Kara Signed-off-by: Al Viro diff --git a/fs/generic_acl.c b/fs/generic_acl.c index 99800e5..6bc9e3a 100644 --- a/fs/generic_acl.c +++ b/fs/generic_acl.c @@ -94,6 +94,7 @@ generic_acl_set(struct dentry *dentry, const char *name, const void *value, if (error < 0) goto failed; inode->i_mode = mode; + inode->i_ctime = CURRENT_TIME; if (error == 0) { posix_acl_release(acl); acl = NULL; -- cgit v0.10.2 From 87e99511ea54510ffb60b98001d108794d5037f8 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 11 Aug 2010 17:05:45 +0200 Subject: kill BH_Ordered flag Instead of abusing a buffer_head flag just add a variant of sync_dirty_buffer which allows passing the exact type of write flag required. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro diff --git a/fs/buffer.c b/fs/buffer.c index 50efa33..6c8ad97 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2912,13 +2912,6 @@ int submit_bh(int rw, struct buffer_head * bh) BUG_ON(buffer_unwritten(bh)); /* - * Mask in barrier bit for a write (could be either a WRITE or a - * WRITE_SYNC - */ - if (buffer_ordered(bh) && (rw & WRITE)) - rw |= WRITE_BARRIER; - - /* * Only clear out a write error when rewriting */ if (test_set_buffer_req(bh) && (rw & WRITE)) @@ -3021,7 +3014,7 @@ EXPORT_SYMBOL(ll_rw_block); * and then start new I/O and then wait upon it. The caller must have a ref on * the buffer_head. */ -int sync_dirty_buffer(struct buffer_head *bh) +int __sync_dirty_buffer(struct buffer_head *bh, int rw) { int ret = 0; @@ -3030,7 +3023,7 @@ int sync_dirty_buffer(struct buffer_head *bh) if (test_clear_buffer_dirty(bh)) { get_bh(bh); bh->b_end_io = end_buffer_write_sync; - ret = submit_bh(WRITE_SYNC, bh); + ret = submit_bh(rw, bh); wait_on_buffer(bh); if (buffer_eopnotsupp(bh)) { clear_buffer_eopnotsupp(bh); @@ -3043,6 +3036,12 @@ int sync_dirty_buffer(struct buffer_head *bh) } return ret; } +EXPORT_SYMBOL(__sync_dirty_buffer); + +int sync_dirty_buffer(struct buffer_head *bh) +{ + return __sync_dirty_buffer(bh, WRITE_SYNC); +} EXPORT_SYMBOL(sync_dirty_buffer); /* diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index 28a9dda..95d8c11 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c @@ -119,7 +119,6 @@ static int journal_write_commit_record(journal_t *journal, struct buffer_head *bh; journal_header_t *header; int ret; - int barrier_done = 0; if (is_journal_aborted(journal)) return 0; @@ -137,34 +136,36 @@ static int journal_write_commit_record(journal_t *journal, JBUFFER_TRACE(descriptor, "write commit block"); set_buffer_dirty(bh); + if (journal->j_flags & JFS_BARRIER) { - set_buffer_ordered(bh); - barrier_done = 1; - } - ret = sync_dirty_buffer(bh); - if (barrier_done) - clear_buffer_ordered(bh); - /* is it possible for another commit to fail at roughly - * the same time as this one? If so, we don't want to - * trust the barrier flag in the super, but instead want - * to remember if we sent a barrier request - */ - if (ret == -EOPNOTSUPP && barrier_done) { - char b[BDEVNAME_SIZE]; + ret = __sync_dirty_buffer(bh, WRITE_SYNC | WRITE_BARRIER); - printk(KERN_WARNING - "JBD: barrier-based sync failed on %s - " - "disabling barriers\n", - bdevname(journal->j_dev, b)); - spin_lock(&journal->j_state_lock); - journal->j_flags &= ~JFS_BARRIER; - spin_unlock(&journal->j_state_lock); + /* + * Is it possible for another commit to fail at roughly + * the same time as this one? If so, we don't want to + * trust the barrier flag in the super, but instead want + * to remember if we sent a barrier request + */ + if (ret == -EOPNOTSUPP) { + char b[BDEVNAME_SIZE]; - /* And try again, without the barrier */ - set_buffer_uptodate(bh); - set_buffer_dirty(bh); + printk(KERN_WARNING + "JBD: barrier-based sync failed on %s - " + "disabling barriers\n", + bdevname(journal->j_dev, b)); + spin_lock(&journal->j_state_lock); + journal->j_flags &= ~JFS_BARRIER; + spin_unlock(&journal->j_state_lock); + + /* And try again, without the barrier */ + set_buffer_uptodate(bh); + set_buffer_dirty(bh); + ret = sync_dirty_buffer(bh); + } + } else { ret = sync_dirty_buffer(bh); } + put_bh(bh); /* One for getblk() */ journal_put_journal_head(descriptor); diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index f52e5e8..7c068c1 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -101,7 +101,6 @@ static int journal_submit_commit_record(journal_t *journal, struct commit_header *tmp; struct buffer_head *bh; int ret; - int barrier_done = 0; struct timespec now = current_kernel_time(); if (is_journal_aborted(journal)) @@ -136,30 +135,22 @@ static int journal_submit_commit_record(journal_t *journal, if (journal->j_flags & JBD2_BARRIER && !JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) { - set_buffer_ordered(bh); - barrier_done = 1; - } - ret = submit_bh(WRITE_SYNC_PLUG, bh); - if (barrier_done) - clear_buffer_ordered(bh); - - /* is it possible for another commit to fail at roughly - * the same time as this one? If so, we don't want to - * trust the barrier flag in the super, but instead want - * to remember if we sent a barrier request - */ - if (ret == -EOPNOTSUPP && barrier_done) { - printk(KERN_WARNING - "JBD2: Disabling barriers on %s, " - "not supported by device\n", journal->j_devname); - write_lock(&journal->j_state_lock); - journal->j_flags &= ~JBD2_BARRIER; - write_unlock(&journal->j_state_lock); + ret = submit_bh(WRITE_SYNC_PLUG | WRITE_BARRIER, bh); + if (ret == -EOPNOTSUPP) { + printk(KERN_WARNING + "JBD2: Disabling barriers on %s, " + "not supported by device\n", journal->j_devname); + write_lock(&journal->j_state_lock); + journal->j_flags &= ~JBD2_BARRIER; + write_unlock(&journal->j_state_lock); - /* And try again, without the barrier */ - lock_buffer(bh); - set_buffer_uptodate(bh); - clear_buffer_dirty(bh); + /* And try again, without the barrier */ + lock_buffer(bh); + set_buffer_uptodate(bh); + clear_buffer_dirty(bh); + ret = submit_bh(WRITE_SYNC_PLUG, bh); + } + } else { ret = submit_bh(WRITE_SYNC_PLUG, bh); } *cbh = bh; diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 1fa86b9..6834543 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -175,24 +175,24 @@ static int nilfs_sync_super(struct nilfs_sb_info *sbi, int flag) { struct the_nilfs *nilfs = sbi->s_nilfs; int err; - int barrier_done = 0; - if (nilfs_test_opt(sbi, BARRIER)) { - set_buffer_ordered(nilfs->ns_sbh[0]); - barrier_done = 1; - } retry: set_buffer_dirty(nilfs->ns_sbh[0]); - err = sync_dirty_buffer(nilfs->ns_sbh[0]); - if (err == -EOPNOTSUPP && barrier_done) { - nilfs_warning(sbi->s_super, __func__, - "barrier-based sync failed. " - "disabling barriers\n"); - nilfs_clear_opt(sbi, BARRIER); - barrier_done = 0; - clear_buffer_ordered(nilfs->ns_sbh[0]); - goto retry; + + if (nilfs_test_opt(sbi, BARRIER)) { + err = __sync_dirty_buffer(nilfs->ns_sbh[0], + WRITE_SYNC | WRITE_BARRIER); + if (err == -EOPNOTSUPP) { + nilfs_warning(sbi->s_super, __func__, + "barrier-based sync failed. " + "disabling barriers\n"); + nilfs_clear_opt(sbi, BARRIER); + goto retry; + } + } else { + err = sync_dirty_buffer(nilfs->ns_sbh[0]); } + if (unlikely(err)) { printk(KERN_ERR "NILFS: unable to write superblock (err=%d)\n", err); diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 43e649a..72c1cf8 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -32,7 +32,6 @@ enum bh_state_bits { BH_Delay, /* Buffer is not yet allocated on disk */ BH_Boundary, /* Block is followed by a discontiguity */ BH_Write_EIO, /* I/O error on write */ - BH_Ordered, /* ordered write */ BH_Eopnotsupp, /* operation not supported (barrier) */ BH_Unwritten, /* Buffer is allocated on disk but not written */ BH_Quiet, /* Buffer Error Prinks to be quiet */ @@ -125,7 +124,6 @@ BUFFER_FNS(Async_Write, async_write) BUFFER_FNS(Delay, delay) BUFFER_FNS(Boundary, boundary) BUFFER_FNS(Write_EIO, write_io_error) -BUFFER_FNS(Ordered, ordered) BUFFER_FNS(Eopnotsupp, eopnotsupp) BUFFER_FNS(Unwritten, unwritten) @@ -183,6 +181,7 @@ void unlock_buffer(struct buffer_head *bh); void __lock_buffer(struct buffer_head *bh); void ll_rw_block(int, int, struct buffer_head * bh[]); int sync_dirty_buffer(struct buffer_head *bh); +int __sync_dirty_buffer(struct buffer_head *bh, int rw); int submit_bh(int, struct buffer_head *); void write_boundary_block(struct block_device *bdev, sector_t bblock, unsigned blocksize); -- cgit v0.10.2 From 9cb569d601e0b93e01c20a22872270ec663b75f6 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 11 Aug 2010 17:06:24 +0200 Subject: remove SWRITE* I/O types These flags aren't real I/O types, but tell ll_rw_block to always lock the buffer instead of giving up on a failed trylock. Instead add a new write_dirty_buffer helper that implements this semantic and use it from the existing SWRITE* callers. Note that the ll_rw_block code had a bug where it didn't promote WRITE_SYNC_PLUG properly, which this patch fixes. In the ufs code clean up the helper that used to call ll_rw_block to mirror sync_dirty_buffer, which is the function it implements for compound buffers. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro diff --git a/fs/buffer.c b/fs/buffer.c index 6c8ad97..3e7dca2 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -770,11 +770,12 @@ static int fsync_buffers_list(spinlock_t *lock, struct list_head *list) spin_unlock(lock); /* * Ensure any pending I/O completes so that - * ll_rw_block() actually writes the current - * contents - it is a noop if I/O is still in - * flight on potentially older contents. + * write_dirty_buffer() actually writes the + * current contents - it is a noop if I/O is + * still in flight on potentially older + * contents. */ - ll_rw_block(SWRITE_SYNC_PLUG, 1, &bh); + write_dirty_buffer(bh, WRITE_SYNC_PLUG); /* * Kick off IO for the previous mapping. Note @@ -2949,22 +2950,21 @@ EXPORT_SYMBOL(submit_bh); /** * ll_rw_block: low-level access to block devices (DEPRECATED) - * @rw: whether to %READ or %WRITE or %SWRITE or maybe %READA (readahead) + * @rw: whether to %READ or %WRITE or maybe %READA (readahead) * @nr: number of &struct buffer_heads in the array * @bhs: array of pointers to &struct buffer_head * * ll_rw_block() takes an array of pointers to &struct buffer_heads, and * requests an I/O operation on them, either a %READ or a %WRITE. The third - * %SWRITE is like %WRITE only we make sure that the *current* data in buffers - * are sent to disk. The fourth %READA option is described in the documentation - * for generic_make_request() which ll_rw_block() calls. + * %READA option is described in the documentation for generic_make_request() + * which ll_rw_block() calls. * * This function drops any buffer that it cannot get a lock on (with the - * BH_Lock state bit) unless SWRITE is required, any buffer that appears to be - * clean when doing a write request, and any buffer that appears to be - * up-to-date when doing read request. Further it marks as clean buffers that - * are processed for writing (the buffer cache won't assume that they are - * actually clean until the buffer gets unlocked). + * BH_Lock state bit), any buffer that appears to be clean when doing a write + * request, and any buffer that appears to be up-to-date when doing read + * request. Further it marks as clean buffers that are processed for + * writing (the buffer cache won't assume that they are actually clean + * until the buffer gets unlocked). * * ll_rw_block sets b_end_io to simple completion handler that marks * the buffer up-to-date (if approriate), unlocks the buffer and wakes @@ -2980,20 +2980,13 @@ void ll_rw_block(int rw, int nr, struct buffer_head *bhs[]) for (i = 0; i < nr; i++) { struct buffer_head *bh = bhs[i]; - if (rw == SWRITE || rw == SWRITE_SYNC || rw == SWRITE_SYNC_PLUG) - lock_buffer(bh); - else if (!trylock_buffer(bh)) + if (!trylock_buffer(bh)) continue; - - if (rw == WRITE || rw == SWRITE || rw == SWRITE_SYNC || - rw == SWRITE_SYNC_PLUG) { + if (rw == WRITE) { if (test_clear_buffer_dirty(bh)) { bh->b_end_io = end_buffer_write_sync; get_bh(bh); - if (rw == SWRITE_SYNC) - submit_bh(WRITE_SYNC, bh); - else - submit_bh(WRITE, bh); + submit_bh(WRITE, bh); continue; } } else { @@ -3009,6 +3002,19 @@ void ll_rw_block(int rw, int nr, struct buffer_head *bhs[]) } EXPORT_SYMBOL(ll_rw_block); +void write_dirty_buffer(struct buffer_head *bh, int rw) +{ + lock_buffer(bh); + if (!test_clear_buffer_dirty(bh)) { + unlock_buffer(bh); + return; + } + bh->b_end_io = end_buffer_write_sync; + get_bh(bh); + submit_bh(rw, bh); +} +EXPORT_SYMBOL(write_dirty_buffer); + /* * For a data-integrity writeout, we need to wait upon any in-progress I/O * and then start new I/O and then wait upon it. The caller must have a ref on diff --git a/fs/fat/misc.c b/fs/fat/misc.c index 1fa23f6..1736f23 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c @@ -250,7 +250,9 @@ int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs) { int i, err = 0; - ll_rw_block(SWRITE, nr_bhs, bhs); + for (i = 0; i < nr_bhs; i++) + write_dirty_buffer(bhs[i], WRITE); + for (i = 0; i < nr_bhs; i++) { wait_on_buffer(bhs[i]); if (buffer_eopnotsupp(bhs[i])) { diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c index b0435dd..05a38b9 100644 --- a/fs/jbd/checkpoint.c +++ b/fs/jbd/checkpoint.c @@ -254,7 +254,9 @@ __flush_batch(journal_t *journal, struct buffer_head **bhs, int *batch_count) { int i; - ll_rw_block(SWRITE, *batch_count, bhs); + for (i = 0; i < *batch_count; i++) + write_dirty_buffer(bhs[i], WRITE); + for (i = 0; i < *batch_count; i++) { struct buffer_head *bh = bhs[i]; clear_buffer_jwrite(bh); diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index f19ce94..2c4b1f1 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -1024,7 +1024,7 @@ void journal_update_superblock(journal_t *journal, int wait) if (wait) sync_dirty_buffer(bh); else - ll_rw_block(SWRITE, 1, &bh); + write_dirty_buffer(bh, WRITE); out: /* If we have just flushed the log (by marking s_start==0), then diff --git a/fs/jbd/revoke.c b/fs/jbd/revoke.c index ad71732..d290183 100644 --- a/fs/jbd/revoke.c +++ b/fs/jbd/revoke.c @@ -617,7 +617,7 @@ static void flush_descriptor(journal_t *journal, set_buffer_jwrite(bh); BUFFER_TRACE(bh, "write"); set_buffer_dirty(bh); - ll_rw_block((write_op == WRITE) ? SWRITE : SWRITE_SYNC_PLUG, 1, &bh); + write_dirty_buffer(bh, write_op); } #endif diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c index 1c23a0f..5247e7f 100644 --- a/fs/jbd2/checkpoint.c +++ b/fs/jbd2/checkpoint.c @@ -255,7 +255,9 @@ __flush_batch(journal_t *journal, int *batch_count) { int i; - ll_rw_block(SWRITE, *batch_count, journal->j_chkpt_bhs); + for (i = 0; i < *batch_count; i++) + write_dirty_buffer(journal->j_chkpt_bhs[i], WRITE); + for (i = 0; i < *batch_count; i++) { struct buffer_head *bh = journal->j_chkpt_bhs[i]; clear_buffer_jwrite(bh); diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index ad5866a..0e8014e 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -1124,7 +1124,7 @@ void jbd2_journal_update_superblock(journal_t *journal, int wait) set_buffer_uptodate(bh); } } else - ll_rw_block(SWRITE, 1, &bh); + write_dirty_buffer(bh, WRITE); out: /* If we have just flushed the log (by marking s_start==0), then diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c index a360b06..9ad321f 100644 --- a/fs/jbd2/revoke.c +++ b/fs/jbd2/revoke.c @@ -625,7 +625,7 @@ static void flush_descriptor(journal_t *journal, set_buffer_jwrite(bh); BUFFER_TRACE(bh, "write"); set_buffer_dirty(bh); - ll_rw_block((write_op == WRITE) ? SWRITE : SWRITE_SYNC_PLUG, 1, &bh); + write_dirty_buffer(bh, write_op); } #endif diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index 1ec952b..812e2c0 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -2311,7 +2311,7 @@ static int journal_read_transaction(struct super_block *sb, /* flush out the real blocks */ for (i = 0; i < get_desc_trans_len(desc); i++) { set_buffer_dirty(real_blocks[i]); - ll_rw_block(SWRITE, 1, real_blocks + i); + write_dirty_buffer(real_blocks[i], WRITE); } for (i = 0; i < get_desc_trans_len(desc); i++) { wait_on_buffer(real_blocks[i]); diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c index 048484f..46f7a80 100644 --- a/fs/ufs/balloc.c +++ b/fs/ufs/balloc.c @@ -114,10 +114,8 @@ void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count) ubh_mark_buffer_dirty (USPI_UBH(uspi)); ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); - if (sb->s_flags & MS_SYNCHRONOUS) { - ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi)); - ubh_wait_on_buffer (UCPI_UBH(ucpi)); - } + if (sb->s_flags & MS_SYNCHRONOUS) + ubh_sync_block(UCPI_UBH(ucpi)); sb->s_dirt = 1; unlock_super (sb); @@ -207,10 +205,8 @@ do_more: ubh_mark_buffer_dirty (USPI_UBH(uspi)); ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); - if (sb->s_flags & MS_SYNCHRONOUS) { - ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi)); - ubh_wait_on_buffer (UCPI_UBH(ucpi)); - } + if (sb->s_flags & MS_SYNCHRONOUS) + ubh_sync_block(UCPI_UBH(ucpi)); if (overflow) { fragment += count; @@ -558,10 +554,8 @@ static u64 ufs_add_fragments(struct inode *inode, u64 fragment, ubh_mark_buffer_dirty (USPI_UBH(uspi)); ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); - if (sb->s_flags & MS_SYNCHRONOUS) { - ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi)); - ubh_wait_on_buffer (UCPI_UBH(ucpi)); - } + if (sb->s_flags & MS_SYNCHRONOUS) + ubh_sync_block(UCPI_UBH(ucpi)); sb->s_dirt = 1; UFSD("EXIT, fragment %llu\n", (unsigned long long)fragment); @@ -680,10 +674,8 @@ cg_found: succed: ubh_mark_buffer_dirty (USPI_UBH(uspi)); ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); - if (sb->s_flags & MS_SYNCHRONOUS) { - ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi)); - ubh_wait_on_buffer (UCPI_UBH(ucpi)); - } + if (sb->s_flags & MS_SYNCHRONOUS) + ubh_sync_block(UCPI_UBH(ucpi)); sb->s_dirt = 1; result += cgno * uspi->s_fpg; diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c index 428017e..2eabf04 100644 --- a/fs/ufs/ialloc.c +++ b/fs/ufs/ialloc.c @@ -113,10 +113,8 @@ void ufs_free_inode (struct inode * inode) ubh_mark_buffer_dirty (USPI_UBH(uspi)); ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); - if (sb->s_flags & MS_SYNCHRONOUS) { - ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi)); - ubh_wait_on_buffer (UCPI_UBH(ucpi)); - } + if (sb->s_flags & MS_SYNCHRONOUS) + ubh_sync_block(UCPI_UBH(ucpi)); sb->s_dirt = 1; unlock_super (sb); @@ -156,10 +154,8 @@ static void ufs2_init_inodes_chunk(struct super_block *sb, fs32_add(sb, &ucg->cg_u.cg_u2.cg_initediblk, uspi->s_inopb); ubh_mark_buffer_dirty(UCPI_UBH(ucpi)); - if (sb->s_flags & MS_SYNCHRONOUS) { - ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi)); - ubh_wait_on_buffer(UCPI_UBH(ucpi)); - } + if (sb->s_flags & MS_SYNCHRONOUS) + ubh_sync_block(UCPI_UBH(ucpi)); UFSD("EXIT\n"); } @@ -290,10 +286,8 @@ cg_found: } ubh_mark_buffer_dirty (USPI_UBH(uspi)); ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); - if (sb->s_flags & MS_SYNCHRONOUS) { - ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi)); - ubh_wait_on_buffer (UCPI_UBH(ucpi)); - } + if (sb->s_flags & MS_SYNCHRONOUS) + ubh_sync_block(UCPI_UBH(ucpi)); sb->s_dirt = 1; inode->i_ino = cg * uspi->s_ipg + bit; diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c index 34d5cb1..a58f915 100644 --- a/fs/ufs/truncate.c +++ b/fs/ufs/truncate.c @@ -243,10 +243,8 @@ static int ufs_trunc_indirect(struct inode *inode, u64 offset, void *p) ubh_bforget(ind_ubh); ind_ubh = NULL; } - if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh)) { - ubh_ll_rw_block(SWRITE, ind_ubh); - ubh_wait_on_buffer (ind_ubh); - } + if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh)) + ubh_sync_block(ind_ubh); ubh_brelse (ind_ubh); UFSD("EXIT: ino %lu\n", inode->i_ino); @@ -307,10 +305,8 @@ static int ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p) ubh_bforget(dind_bh); dind_bh = NULL; } - if (IS_SYNC(inode) && dind_bh && ubh_buffer_dirty(dind_bh)) { - ubh_ll_rw_block(SWRITE, dind_bh); - ubh_wait_on_buffer (dind_bh); - } + if (IS_SYNC(inode) && dind_bh && ubh_buffer_dirty(dind_bh)) + ubh_sync_block(dind_bh); ubh_brelse (dind_bh); UFSD("EXIT: ino %lu\n", inode->i_ino); @@ -367,10 +363,8 @@ static int ufs_trunc_tindirect(struct inode *inode) ubh_bforget(tind_bh); tind_bh = NULL; } - if (IS_SYNC(inode) && tind_bh && ubh_buffer_dirty(tind_bh)) { - ubh_ll_rw_block(SWRITE, tind_bh); - ubh_wait_on_buffer (tind_bh); - } + if (IS_SYNC(inode) && tind_bh && ubh_buffer_dirty(tind_bh)) + ubh_sync_block(tind_bh); ubh_brelse (tind_bh); UFSD("EXIT: ino %lu\n", inode->i_ino); diff --git a/fs/ufs/util.c b/fs/ufs/util.c index 85a7fc9..d2c36d5 100644 --- a/fs/ufs/util.c +++ b/fs/ufs/util.c @@ -113,21 +113,17 @@ void ubh_mark_buffer_uptodate (struct ufs_buffer_head * ubh, int flag) } } -void ubh_ll_rw_block(int rw, struct ufs_buffer_head *ubh) +void ubh_sync_block(struct ufs_buffer_head *ubh) { - if (!ubh) - return; + if (ubh) { + unsigned i; - ll_rw_block(rw, ubh->count, ubh->bh); -} + for (i = 0; i < ubh->count; i++) + write_dirty_buffer(ubh->bh[i], WRITE); -void ubh_wait_on_buffer (struct ufs_buffer_head * ubh) -{ - unsigned i; - if (!ubh) - return; - for ( i = 0; i < ubh->count; i++ ) - wait_on_buffer (ubh->bh[i]); + for (i = 0; i < ubh->count; i++) + wait_on_buffer(ubh->bh[i]); + } } void ubh_bforget (struct ufs_buffer_head * ubh) diff --git a/fs/ufs/util.h b/fs/ufs/util.h index 0466036..9f8775c 100644 --- a/fs/ufs/util.h +++ b/fs/ufs/util.h @@ -269,8 +269,7 @@ extern void ubh_brelse (struct ufs_buffer_head *); extern void ubh_brelse_uspi (struct ufs_sb_private_info *); extern void ubh_mark_buffer_dirty (struct ufs_buffer_head *); extern void ubh_mark_buffer_uptodate (struct ufs_buffer_head *, int); -extern void ubh_ll_rw_block(int, struct ufs_buffer_head *); -extern void ubh_wait_on_buffer (struct ufs_buffer_head *); +extern void ubh_sync_block(struct ufs_buffer_head *); extern void ubh_bforget (struct ufs_buffer_head *); extern int ubh_buffer_dirty (struct ufs_buffer_head *); #define ubh_ubhcpymem(mem,ubh,size) _ubh_ubhcpymem_(uspi,mem,ubh,size) diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 72c1cf8..ec94c12 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -182,6 +182,7 @@ void __lock_buffer(struct buffer_head *bh); void ll_rw_block(int, int, struct buffer_head * bh[]); int sync_dirty_buffer(struct buffer_head *bh); int __sync_dirty_buffer(struct buffer_head *bh, int rw); +void write_dirty_buffer(struct buffer_head *bh, int rw); int submit_bh(int, struct buffer_head *); void write_boundary_block(struct block_device *bdev, sector_t bblock, unsigned blocksize); diff --git a/include/linux/fs.h b/include/linux/fs.h index 9a96b4d..29f7c97 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -125,9 +125,6 @@ struct inodes_stat_t { * block layer could (in theory) choose to ignore this * request if it runs into resource problems. * WRITE A normal async write. Device will be plugged. - * SWRITE Like WRITE, but a special case for ll_rw_block() that - * tells it to lock the buffer first. Normally a buffer - * must be locked before doing IO. * WRITE_SYNC_PLUG Synchronous write. Identical to WRITE, but passes down * the hint that someone will be waiting on this IO * shortly. The device must still be unplugged explicitly, @@ -138,9 +135,6 @@ struct inodes_stat_t { * immediately after submission. The write equivalent * of READ_SYNC. * WRITE_ODIRECT_PLUG Special case write for O_DIRECT only. - * SWRITE_SYNC - * SWRITE_SYNC_PLUG Like WRITE_SYNC/WRITE_SYNC_PLUG, but locks the buffer. - * See SWRITE. * WRITE_BARRIER Like WRITE_SYNC, but tells the block layer that all * previously submitted writes must be safely on storage * before this one is started. Also guarantees that when @@ -155,7 +149,6 @@ struct inodes_stat_t { #define READ 0 #define WRITE RW_MASK #define READA RWA_MASK -#define SWRITE (WRITE | READA) #define READ_SYNC (READ | REQ_SYNC | REQ_UNPLUG) #define READ_META (READ | REQ_META) @@ -165,8 +158,6 @@ struct inodes_stat_t { #define WRITE_META (WRITE | REQ_META) #define WRITE_BARRIER (WRITE | REQ_SYNC | REQ_NOIDLE | REQ_UNPLUG | \ REQ_HARDBARRIER) -#define SWRITE_SYNC_PLUG (SWRITE | REQ_SYNC | REQ_NOIDLE) -#define SWRITE_SYNC (SWRITE | REQ_SYNC | REQ_NOIDLE | REQ_UNPLUG) /* * These aren't really reads or writes, they pass down information about -- cgit v0.10.2 From 9b3bb86acabe0c05923cea1ed3b0bee9439fef4b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 17 Aug 2010 22:49:26 -0700 Subject: sparc64: Make rwsems 64-bit. Basically tip-off the powerpc code, use a 64-bit type and atomic64_t interfaces for the implementation. This gets us off of the by-hand asm code I wrote, which frankly I think probably ruins I-cache hit rates. The idea was the keep the call chains less deep, but anything taking the rw-semaphores probably is also calling other stuff and therefore already has allocated a stack-frame. So no real stack frame savings ever. Ben H. has posted patches to make powerpc use 64-bit too and with some abstractions we can probably use a shared header file somewhere. With suggestions from Sam Ravnborg. Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/rwsem-const.h b/arch/sparc/include/asm/rwsem-const.h deleted file mode 100644 index e4c61a1..0000000 --- a/arch/sparc/include/asm/rwsem-const.h +++ /dev/null @@ -1,12 +0,0 @@ -/* rwsem-const.h: RW semaphore counter constants. */ -#ifndef _SPARC64_RWSEM_CONST_H -#define _SPARC64_RWSEM_CONST_H - -#define RWSEM_UNLOCKED_VALUE 0x00000000 -#define RWSEM_ACTIVE_BIAS 0x00000001 -#define RWSEM_ACTIVE_MASK 0x0000ffff -#define RWSEM_WAITING_BIAS (-0x00010000) -#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS -#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) - -#endif /* _SPARC64_RWSEM_CONST_H */ diff --git a/arch/sparc/include/asm/rwsem.h b/arch/sparc/include/asm/rwsem.h index 6e56210..a2b4302 100644 --- a/arch/sparc/include/asm/rwsem.h +++ b/arch/sparc/include/asm/rwsem.h @@ -15,16 +15,21 @@ #include #include -#include struct rwsem_waiter; struct rw_semaphore { - signed int count; - spinlock_t wait_lock; - struct list_head wait_list; + signed long count; +#define RWSEM_UNLOCKED_VALUE 0x00000000L +#define RWSEM_ACTIVE_BIAS 0x00000001L +#define RWSEM_ACTIVE_MASK 0xffffffffL +#define RWSEM_WAITING_BIAS (-RWSEM_ACTIVE_MASK-1) +#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS +#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) + spinlock_t wait_lock; + struct list_head wait_list; #ifdef CONFIG_DEBUG_LOCK_ALLOC - struct lockdep_map dep_map; + struct lockdep_map dep_map; #endif }; @@ -41,6 +46,11 @@ struct rw_semaphore { #define DECLARE_RWSEM(name) \ struct rw_semaphore name = __RWSEM_INITIALIZER(name) +extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem); +extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem); +extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem); +extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem); + extern void __init_rwsem(struct rw_semaphore *sem, const char *name, struct lock_class_key *key); @@ -51,27 +61,103 @@ do { \ __init_rwsem((sem), #sem, &__key); \ } while (0) -extern void __down_read(struct rw_semaphore *sem); -extern int __down_read_trylock(struct rw_semaphore *sem); -extern void __down_write(struct rw_semaphore *sem); -extern int __down_write_trylock(struct rw_semaphore *sem); -extern void __up_read(struct rw_semaphore *sem); -extern void __up_write(struct rw_semaphore *sem); -extern void __downgrade_write(struct rw_semaphore *sem); +/* + * lock for reading + */ +static inline void __down_read(struct rw_semaphore *sem) +{ + if (unlikely(atomic64_inc_return((atomic64_t *)(&sem->count)) <= 0L)) + rwsem_down_read_failed(sem); +} + +static inline int __down_read_trylock(struct rw_semaphore *sem) +{ + long tmp; + + while ((tmp = sem->count) >= 0L) { + if (tmp == cmpxchg(&sem->count, tmp, + tmp + RWSEM_ACTIVE_READ_BIAS)) { + return 1; + } + } + return 0; +} +/* + * lock for writing + */ static inline void __down_write_nested(struct rw_semaphore *sem, int subclass) { - __down_write(sem); + long tmp; + + tmp = atomic64_add_return(RWSEM_ACTIVE_WRITE_BIAS, + (atomic64_t *)(&sem->count)); + if (unlikely(tmp != RWSEM_ACTIVE_WRITE_BIAS)) + rwsem_down_write_failed(sem); } -static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem) +static inline void __down_write(struct rw_semaphore *sem) { - return atomic_add_return(delta, (atomic_t *)(&sem->count)); + __down_write_nested(sem, 0); +} + +static inline int __down_write_trylock(struct rw_semaphore *sem) +{ + long tmp; + + tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE, + RWSEM_ACTIVE_WRITE_BIAS); + return tmp == RWSEM_UNLOCKED_VALUE; } -static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem) +/* + * unlock after reading + */ +static inline void __up_read(struct rw_semaphore *sem) +{ + long tmp; + + tmp = atomic64_dec_return((atomic64_t *)(&sem->count)); + if (unlikely(tmp < -1L && (tmp & RWSEM_ACTIVE_MASK) == 0L)) + rwsem_wake(sem); +} + +/* + * unlock after writing + */ +static inline void __up_write(struct rw_semaphore *sem) +{ + if (unlikely(atomic64_sub_return(RWSEM_ACTIVE_WRITE_BIAS, + (atomic64_t *)(&sem->count)) < 0L)) + rwsem_wake(sem); +} + +/* + * implement atomic add functionality + */ +static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem) +{ + atomic64_add(delta, (atomic64_t *)(&sem->count)); +} + +/* + * downgrade write lock to read lock + */ +static inline void __downgrade_write(struct rw_semaphore *sem) +{ + long tmp; + + tmp = atomic64_add_return(-RWSEM_WAITING_BIAS, (atomic64_t *)(&sem->count)); + if (tmp < 0L) + rwsem_downgrade_wake(sem); +} + +/* + * implement exchange and add functionality + */ +static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem) { - atomic_add(delta, (atomic_t *)(&sem->count)); + return atomic64_add_return(delta, (atomic64_t *)(&sem->count)); } static inline int rwsem_is_locked(struct rw_semaphore *sem) diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile index c4b5e03..846d1c4 100644 --- a/arch/sparc/lib/Makefile +++ b/arch/sparc/lib/Makefile @@ -15,7 +15,7 @@ lib-$(CONFIG_SPARC32) += divdi3.o udivdi3.o lib-$(CONFIG_SPARC32) += copy_user.o locks.o lib-y += atomic_$(BITS).o lib-$(CONFIG_SPARC32) += lshrdi3.o ashldi3.o -lib-y += rwsem_$(BITS).o +lib-$(CONFIG_SPARC32) += rwsem_32.o lib-$(CONFIG_SPARC32) += muldi3.o bitext.o cmpdi2.o lib-$(CONFIG_SPARC64) += copy_page.o clear_page.o bzero.o diff --git a/arch/sparc/lib/rwsem_64.S b/arch/sparc/lib/rwsem_64.S deleted file mode 100644 index 91a7d29..0000000 --- a/arch/sparc/lib/rwsem_64.S +++ /dev/null @@ -1,163 +0,0 @@ -/* rwsem.S: RW semaphore assembler. - * - * Written by David S. Miller (davem@redhat.com), 2001. - * Derived from asm-i386/rwsem.h - */ - -#include - - .section .sched.text, "ax" - - .globl __down_read -__down_read: -1: lduw [%o0], %g1 - add %g1, 1, %g7 - cas [%o0], %g1, %g7 - cmp %g1, %g7 - bne,pn %icc, 1b - add %g7, 1, %g7 - cmp %g7, 0 - bl,pn %icc, 3f - nop -2: - retl - nop -3: - save %sp, -192, %sp - call rwsem_down_read_failed - mov %i0, %o0 - ret - restore - .size __down_read, .-__down_read - - .globl __down_read_trylock -__down_read_trylock: -1: lduw [%o0], %g1 - add %g1, 1, %g7 - cmp %g7, 0 - bl,pn %icc, 2f - mov 0, %o1 - cas [%o0], %g1, %g7 - cmp %g1, %g7 - bne,pn %icc, 1b - mov 1, %o1 -2: retl - mov %o1, %o0 - .size __down_read_trylock, .-__down_read_trylock - - .globl __down_write -__down_write: - sethi %hi(RWSEM_ACTIVE_WRITE_BIAS), %g1 - or %g1, %lo(RWSEM_ACTIVE_WRITE_BIAS), %g1 -1: - lduw [%o0], %g3 - add %g3, %g1, %g7 - cas [%o0], %g3, %g7 - cmp %g3, %g7 - bne,pn %icc, 1b - cmp %g7, 0 - bne,pn %icc, 3f - nop -2: retl - nop -3: - save %sp, -192, %sp - call rwsem_down_write_failed - mov %i0, %o0 - ret - restore - .size __down_write, .-__down_write - - .globl __down_write_trylock -__down_write_trylock: - sethi %hi(RWSEM_ACTIVE_WRITE_BIAS), %g1 - or %g1, %lo(RWSEM_ACTIVE_WRITE_BIAS), %g1 -1: - lduw [%o0], %g3 - cmp %g3, 0 - bne,pn %icc, 2f - mov 0, %o1 - add %g3, %g1, %g7 - cas [%o0], %g3, %g7 - cmp %g3, %g7 - bne,pn %icc, 1b - mov 1, %o1 -2: retl - mov %o1, %o0 - .size __down_write_trylock, .-__down_write_trylock - - .globl __up_read -__up_read: -1: - lduw [%o0], %g1 - sub %g1, 1, %g7 - cas [%o0], %g1, %g7 - cmp %g1, %g7 - bne,pn %icc, 1b - cmp %g7, 0 - bl,pn %icc, 3f - nop -2: retl - nop -3: sethi %hi(RWSEM_ACTIVE_MASK), %g1 - sub %g7, 1, %g7 - or %g1, %lo(RWSEM_ACTIVE_MASK), %g1 - andcc %g7, %g1, %g0 - bne,pn %icc, 2b - nop - save %sp, -192, %sp - call rwsem_wake - mov %i0, %o0 - ret - restore - .size __up_read, .-__up_read - - .globl __up_write -__up_write: - sethi %hi(RWSEM_ACTIVE_WRITE_BIAS), %g1 - or %g1, %lo(RWSEM_ACTIVE_WRITE_BIAS), %g1 -1: - lduw [%o0], %g3 - sub %g3, %g1, %g7 - cas [%o0], %g3, %g7 - cmp %g3, %g7 - bne,pn %icc, 1b - sub %g7, %g1, %g7 - cmp %g7, 0 - bl,pn %icc, 3f - nop -2: - retl - nop -3: - save %sp, -192, %sp - call rwsem_wake - mov %i0, %o0 - ret - restore - .size __up_write, .-__up_write - - .globl __downgrade_write -__downgrade_write: - sethi %hi(RWSEM_WAITING_BIAS), %g1 - or %g1, %lo(RWSEM_WAITING_BIAS), %g1 -1: - lduw [%o0], %g3 - sub %g3, %g1, %g7 - cas [%o0], %g3, %g7 - cmp %g3, %g7 - bne,pn %icc, 1b - sub %g7, %g1, %g7 - cmp %g7, 0 - bl,pn %icc, 3f - nop -2: - retl - nop -3: - save %sp, -192, %sp - call rwsem_downgrade_wake - mov %i0, %o0 - ret - restore - .size __downgrade_write, .-__downgrade_write -- cgit v0.10.2 From 2c7d46ec192e4f2b350f67a0e185b9bce646cd6b Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 18 Aug 2010 16:16:05 +1000 Subject: md raid-1/10 Fix bio_rw bit manipulations again commit 7b6d91daee5cac6402186ff224c3af39d79f4a0e changed the behaviour of a few variables in raid1 and raid10 from flags to bit-sets, but left them as type 'bool' so they did not work. Change them (back) to unsigned long. (historical note: see 1ef04fefe2241087d9db7e9615c3f11b516e36cf) Signed-off-by: NeilBrown Reported-by: Jiri Slaby and many others diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 64d9652..ad83a4d 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -787,8 +787,8 @@ static int make_request(mddev_t *mddev, struct bio * bio) struct bio_list bl; struct page **behind_pages = NULL; const int rw = bio_data_dir(bio); - const bool do_sync = (bio->bi_rw & REQ_SYNC); - bool do_barriers; + const unsigned long do_sync = (bio->bi_rw & REQ_SYNC); + unsigned long do_barriers; mdk_rdev_t *blocked_rdev; /* @@ -1643,7 +1643,7 @@ static void raid1d(mddev_t *mddev) * We already have a nr_pending reference on these rdevs. */ int i; - const bool do_sync = (r1_bio->master_bio->bi_rw & REQ_SYNC); + const unsigned long do_sync = (r1_bio->master_bio->bi_rw & REQ_SYNC); clear_bit(R1BIO_BarrierRetry, &r1_bio->state); clear_bit(R1BIO_Barrier, &r1_bio->state); for (i=0; i < conf->raid_disks; i++) @@ -1699,7 +1699,7 @@ static void raid1d(mddev_t *mddev) (unsigned long long)r1_bio->sector); raid_end_bio_io(r1_bio); } else { - const bool do_sync = r1_bio->master_bio->bi_rw & REQ_SYNC; + const unsigned long do_sync = r1_bio->master_bio->bi_rw & REQ_SYNC; r1_bio->bios[r1_bio->read_disk] = mddev->ro ? IO_BLOCKED : NULL; r1_bio->read_disk = disk; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index a2f8a71..8471838 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -799,7 +799,7 @@ static int make_request(mddev_t *mddev, struct bio * bio) int i; int chunk_sects = conf->chunk_mask + 1; const int rw = bio_data_dir(bio); - const bool do_sync = (bio->bi_rw & REQ_SYNC); + const unsigned long do_sync = (bio->bi_rw & REQ_SYNC); struct bio_list bl; unsigned long flags; mdk_rdev_t *blocked_rdev; @@ -1737,7 +1737,7 @@ static void raid10d(mddev_t *mddev) raid_end_bio_io(r10_bio); bio_put(bio); } else { - const bool do_sync = (r10_bio->master_bio->bi_rw & REQ_SYNC); + const unsigned long do_sync = (r10_bio->master_bio->bi_rw & REQ_SYNC); bio_put(bio); rdev = conf->mirrors[mirror].rdev; if (printk_ratelimit()) -- cgit v0.10.2 From 850a496f969719b494cc972ab1d0e088737358d7 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 18 Aug 2010 06:18:57 -0400 Subject: hostfs: dumb (and usually harmless) tpyo - strncpy instead of strlcpy ... not harmless in this case - we have a string in the end of buffer already. Signed-off-by: Al Viro diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index dd1e555..77c4f6e 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -104,7 +104,7 @@ static char *__dentry_name(struct dentry *dentry, char *name) __putname(name); return NULL; } - strncpy(name, root, PATH_MAX); + strlcpy(name, root, PATH_MAX); if (len > p - name) { __putname(name); return NULL; -- cgit v0.10.2 From 3b6036d148bad5bb7928b021a49bb9e395361084 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 18 Aug 2010 06:21:10 -0400 Subject: hostfs ->follow_link() braino we want the assignment to err done inside the if () to be visible after it, so (re)declaring err inside if () body is wrong. Signed-off-by: Al Viro diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 77c4f6e..f7dc9b5 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -876,7 +876,7 @@ static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd) char *path = dentry_name(dentry); int err = -ENOMEM; if (path) { - int err = hostfs_do_readlink(path, link, PATH_MAX); + err = hostfs_do_readlink(path, link, PATH_MAX); if (err == PATH_MAX) err = -E2BIG; __putname(path); -- cgit v0.10.2 From 3a48ee8a4ad26c3a538b6fc11a86a8f80c3dce18 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Mon, 16 Aug 2010 19:05:23 +0200 Subject: mbcache: Limit the maximum number of cache entries Limit the maximum number of mb_cache entries depending on the number of hash buckets: if the only limit to the number of cache entries is the available memory the hash chains can grow very long, taking a long time to search. At least partially solves https://bugzilla.lustre.org/show_bug.cgi?id=22771. Signed-off-by: Andreas Gruenbacher Signed-off-by: Al Viro diff --git a/fs/mbcache.c b/fs/mbcache.c index cf4e6cd..9344474 100644 --- a/fs/mbcache.c +++ b/fs/mbcache.c @@ -80,6 +80,7 @@ struct mb_cache { struct list_head c_cache_list; const char *c_name; atomic_t c_entry_count; + int c_max_entries; int c_bucket_bits; struct kmem_cache *c_entry_cache; struct list_head *c_block_hash; @@ -243,6 +244,12 @@ mb_cache_create(const char *name, int bucket_bits) if (!cache->c_entry_cache) goto fail2; + /* + * Set an upper limit on the number of cache entries so that the hash + * chains won't grow too long. + */ + cache->c_max_entries = bucket_count << 4; + spin_lock(&mb_cache_spinlock); list_add(&cache->c_cache_list, &mb_cache_list); spin_unlock(&mb_cache_spinlock); @@ -333,7 +340,6 @@ mb_cache_destroy(struct mb_cache *cache) kfree(cache); } - /* * mb_cache_entry_alloc() * @@ -345,17 +351,29 @@ mb_cache_destroy(struct mb_cache *cache) struct mb_cache_entry * mb_cache_entry_alloc(struct mb_cache *cache, gfp_t gfp_flags) { - struct mb_cache_entry *ce; - - ce = kmem_cache_alloc(cache->c_entry_cache, gfp_flags); - if (ce) { + struct mb_cache_entry *ce = NULL; + + if (atomic_read(&cache->c_entry_count) >= cache->c_max_entries) { + spin_lock(&mb_cache_spinlock); + if (!list_empty(&mb_cache_lru_list)) { + ce = list_entry(mb_cache_lru_list.next, + struct mb_cache_entry, e_lru_list); + list_del_init(&ce->e_lru_list); + __mb_cache_entry_unhash(ce); + } + spin_unlock(&mb_cache_spinlock); + } + if (!ce) { + ce = kmem_cache_alloc(cache->c_entry_cache, gfp_flags); + if (!ce) + return NULL; atomic_inc(&cache->c_entry_count); INIT_LIST_HEAD(&ce->e_lru_list); INIT_LIST_HEAD(&ce->e_block_list); ce->e_cache = cache; - ce->e_used = 1 + MB_CACHE_WRITER; ce->e_queued = 0; } + ce->e_used = 1 + MB_CACHE_WRITER; return ce; } -- cgit v0.10.2 From 93b352fce679945845664b56b0c3afbd655a7a12 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 16 Aug 2010 16:09:09 +0800 Subject: pxa3xx: fix ns2cycle equation Test on a PXA310 platform with Samsung K9F2G08X0B NAND flash, with tCH=5 and clk is 156MHz, ns2cycle(5, 156000000) returns -1. ns2cycle returns negtive value will break NDTR0_tXX macros. After checking the commit log, I found the problem is introduced by commit 5b0d4d7c8a67c5ba3d35e6ceb0c5530cc6846db7 "[MTD] [NAND] pxa3xx: convert from ns to clock ticks more accurately" To get num of clock cycles, we use below equation: num of clock cycles = time (ns) / one clock cycle (ns) + 1 We need to add 1 cycle here because integer division will truncate the result. It is possible the developers set the Min values in SPEC for timing settings. Thus the truncate may cause problem, and it is safe to add an extra cycle here. The various fields in NDTR{01} are in units of clock ticks minus one, thus we should subtract 1 cycle then. Thus the correct equation should be: num of clock cycles = time (ns) / one clock cycle (ns) + 1 - 1 = time (ns) / one clock cycle (ns) Signed-off-by: Axel Lin Signed-off-by: Lei Wen Acked-by: Eric Miao Signed-off-by: David Woodhouse Cc: stable@kernel.org diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index e02fa4f..4d89f37 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -363,7 +363,7 @@ static struct pxa3xx_nand_flash *builtin_flash_types[] = { #define tAR_NDTR1(r) (((r) >> 0) & 0xf) /* convert nano-seconds to nand flash controller clock cycles */ -#define ns2cycle(ns, clk) (int)(((ns) * (clk / 1000000) / 1000) - 1) +#define ns2cycle(ns, clk) (int)((ns) * (clk / 1000000) / 1000) /* convert nand flash controller clock cycles to nano-seconds */ #define cycle2ns(c, clk) ((((c) + 1) * 1000000 + clk / 500) / (clk / 1000)) -- cgit v0.10.2 From 2e2e88ea8c3bd9e1bd6e42faf047a4ac3fbb3b2f Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 18 Aug 2010 04:37:30 +1000 Subject: fs: fix do_lookup false negative fs: fix do_lookup false negative In do_lookup, if we initially find no dentry, we take the directory i_mutex and re-check the lookup. If we find a dentry there, then we revalidate it if needed. However if that revalidate asks for the dentry to be invalidated, we return -ENOENT from do_lookup. What should happen instead is an attempt to allocate and lookup a new dentry. This is probably not noticed because it is rare. It is only reached if a concurrent create races in first (in which case, the dentry probably won't be invalidated anyway), or if the racy __d_lookup has failed due to a false-negative (which is very rare). Fix this by removing code and have it use the normal reval path. Signed-off-by: Nick Piggin Signed-off-by: Al Viro diff --git a/fs/namei.c b/fs/namei.c index 17ea76b..c2742b7 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -709,6 +709,7 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, dentry = __d_lookup(nd->path.dentry, name); if (!dentry) goto need_lookup; +found: if (dentry->d_op && dentry->d_op->d_revalidate) goto need_revalidate; done: @@ -766,14 +767,7 @@ out_unlock: * we waited on the semaphore. Need to revalidate. */ mutex_unlock(&dir->i_mutex); - if (dentry->d_op && dentry->d_op->d_revalidate) { - dentry = do_revalidate(dentry, nd); - if (!dentry) - dentry = ERR_PTR(-ENOENT); - } - if (IS_ERR(dentry)) - goto fail; - goto done; + goto found; need_revalidate: dentry = do_revalidate(dentry, nd); -- cgit v0.10.2 From baa0389073eb7beb9d36f6d13df97e16c1bfa626 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 18 Aug 2010 04:37:31 +1000 Subject: fs: dentry allocation consolidation fs: dentry allocation consolidation There are 2 duplicate copies of code in dentry allocation in path lookup. Consolidate them into a single function. Signed-off-by: Nick Piggin Signed-off-by: Al Viro diff --git a/fs/namei.c b/fs/namei.c index c2742b7..b815a4d 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -686,6 +686,35 @@ static __always_inline void follow_dotdot(struct nameidata *nd) } /* + * Allocate a dentry with name and parent, and perform a parent + * directory ->lookup on it. Returns the new dentry, or ERR_PTR + * on error. parent->d_inode->i_mutex must be held. d_lookup must + * have verified that no child exists while under i_mutex. + */ +static struct dentry *d_alloc_and_lookup(struct dentry *parent, + struct qstr *name, struct nameidata *nd) +{ + struct inode *inode = parent->d_inode; + struct dentry *dentry; + struct dentry *old; + + /* Don't create child dentry for a dead directory. */ + if (unlikely(IS_DEADDIR(inode))) + return ERR_PTR(-ENOENT); + + dentry = d_alloc(parent, name); + if (unlikely(!dentry)) + return ERR_PTR(-ENOMEM); + + old = inode->i_op->lookup(inode, dentry, nd); + if (unlikely(old)) { + dput(dentry); + dentry = old; + } + return dentry; +} + +/* * It's more convoluted than I'd like it to be, but... it's still fairly * small and for now I'd prefer to have fast path as straight as possible. * It _is_ time-critical. @@ -738,30 +767,13 @@ need_lookup: * so doing d_lookup() (with seqlock), instead of lockfree __d_lookup */ dentry = d_lookup(parent, name); - if (!dentry) { - struct dentry *new; - - /* Don't create child dentry for a dead directory. */ - dentry = ERR_PTR(-ENOENT); - if (IS_DEADDIR(dir)) - goto out_unlock; - - new = d_alloc(parent, name); - dentry = ERR_PTR(-ENOMEM); - if (new) { - dentry = dir->i_op->lookup(dir, new, nd); - if (dentry) - dput(new); - else - dentry = new; - } -out_unlock: + if (likely(!dentry)) { + dentry = d_alloc_and_lookup(parent, name, nd); mutex_unlock(&dir->i_mutex); if (IS_ERR(dentry)) goto fail; goto done; } - /* * Uhhuh! Nasty case: the cache was re-populated while * we waited on the semaphore. Need to revalidate. @@ -1135,24 +1147,8 @@ static struct dentry *__lookup_hash(struct qstr *name, if (dentry && dentry->d_op && dentry->d_op->d_revalidate) dentry = do_revalidate(dentry, nd); - if (!dentry) { - struct dentry *new; - - /* Don't create child dentry for a dead directory. */ - dentry = ERR_PTR(-ENOENT); - if (IS_DEADDIR(inode)) - goto out; - - new = d_alloc(base, name); - dentry = ERR_PTR(-ENOMEM); - if (!new) - goto out; - dentry = inode->i_op->lookup(inode, new, nd); - if (!dentry) - dentry = new; - else - dput(new); - } + if (!dentry) + dentry = d_alloc_and_lookup(base, name, nd); out: return dentry; } -- cgit v0.10.2 From 44672e4fbd40e2dda8bbce7d0f71d24dbfc7e00e Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 18 Aug 2010 04:37:32 +1000 Subject: apparmor: use task path helpers apparmor: use task path helpers Signed-off-by: Nick Piggin Signed-off-by: Al Viro diff --git a/security/apparmor/path.c b/security/apparmor/path.c index 96bab94..19358dc 100644 --- a/security/apparmor/path.c +++ b/security/apparmor/path.c @@ -62,19 +62,14 @@ static int d_namespace_path(struct path *path, char *buf, int buflen, int deleted, connected; int error = 0; - /* Get the root we want to resolve too */ + /* Get the root we want to resolve too, released below */ if (flags & PATH_CHROOT_REL) { /* resolve paths relative to chroot */ - read_lock(¤t->fs->lock); - root = current->fs->root; - /* released below */ - path_get(&root); - read_unlock(¤t->fs->lock); + get_fs_root(current->fs, &root); } else { /* resolve paths relative to namespace */ root.mnt = current->nsproxy->mnt_ns->root; root.dentry = root.mnt->mnt_root; - /* released below */ path_get(&root); } -- cgit v0.10.2 From 2a4419b5b2a77f3f4537c14f7ad7df95770655dd Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 18 Aug 2010 04:37:33 +1000 Subject: fs: fs_struct rwlock to spinlock fs: fs_struct rwlock to spinlock struct fs_struct.lock is an rwlock with the read-side used to protect root and pwd members while taking references to them. Taking a reference to a path typically requires just 2 atomic ops, so the critical section is very small. Parallel read-side operations would have cacheline contention on the lock, the dentry, and the vfsmount cachelines, so the rwlock is unlikely to ever give a real parallelism increase. Replace it with a spinlock to avoid one or two atomic operations in typical path lookup fastpath. Signed-off-by: Nick Piggin Signed-off-by: Al Viro diff --git a/drivers/staging/pohmelfs/path_entry.c b/drivers/staging/pohmelfs/path_entry.c index cdc4dd5..8ec83d2 100644 --- a/drivers/staging/pohmelfs/path_entry.c +++ b/drivers/staging/pohmelfs/path_entry.c @@ -44,9 +44,9 @@ int pohmelfs_construct_path_string(struct pohmelfs_inode *pi, void *data, int le return -ENOENT; } - read_lock(¤t->fs->lock); + spin_lock(¤t->fs->lock); path.mnt = mntget(current->fs->root.mnt); - read_unlock(¤t->fs->lock); + spin_unlock(¤t->fs->lock); path.dentry = d; @@ -91,9 +91,9 @@ int pohmelfs_path_length(struct pohmelfs_inode *pi) return -ENOENT; } - read_lock(¤t->fs->lock); + spin_lock(¤t->fs->lock); root = dget(current->fs->root.dentry); - read_unlock(¤t->fs->lock); + spin_unlock(¤t->fs->lock); spin_lock(&dcache_lock); diff --git a/fs/exec.c b/fs/exec.c index 7761837..5adab2c 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1117,7 +1117,7 @@ int check_unsafe_exec(struct linux_binprm *bprm) bprm->unsafe = tracehook_unsafe_exec(p); n_fs = 1; - write_lock(&p->fs->lock); + spin_lock(&p->fs->lock); rcu_read_lock(); for (t = next_thread(p); t != p; t = next_thread(t)) { if (t->fs == p->fs) @@ -1134,7 +1134,7 @@ int check_unsafe_exec(struct linux_binprm *bprm) res = 1; } } - write_unlock(&p->fs->lock); + spin_unlock(&p->fs->lock); return res; } diff --git a/fs/fs_struct.c b/fs/fs_struct.c index 1ee40eb..ed45a9c 100644 --- a/fs/fs_struct.c +++ b/fs/fs_struct.c @@ -13,11 +13,11 @@ void set_fs_root(struct fs_struct *fs, struct path *path) { struct path old_root; - write_lock(&fs->lock); + spin_lock(&fs->lock); old_root = fs->root; fs->root = *path; path_get(path); - write_unlock(&fs->lock); + spin_unlock(&fs->lock); if (old_root.dentry) path_put(&old_root); } @@ -30,11 +30,11 @@ void set_fs_pwd(struct fs_struct *fs, struct path *path) { struct path old_pwd; - write_lock(&fs->lock); + spin_lock(&fs->lock); old_pwd = fs->pwd; fs->pwd = *path; path_get(path); - write_unlock(&fs->lock); + spin_unlock(&fs->lock); if (old_pwd.dentry) path_put(&old_pwd); @@ -51,7 +51,7 @@ void chroot_fs_refs(struct path *old_root, struct path *new_root) task_lock(p); fs = p->fs; if (fs) { - write_lock(&fs->lock); + spin_lock(&fs->lock); if (fs->root.dentry == old_root->dentry && fs->root.mnt == old_root->mnt) { path_get(new_root); @@ -64,7 +64,7 @@ void chroot_fs_refs(struct path *old_root, struct path *new_root) fs->pwd = *new_root; count++; } - write_unlock(&fs->lock); + spin_unlock(&fs->lock); } task_unlock(p); } while_each_thread(g, p); @@ -87,10 +87,10 @@ void exit_fs(struct task_struct *tsk) if (fs) { int kill; task_lock(tsk); - write_lock(&fs->lock); + spin_lock(&fs->lock); tsk->fs = NULL; kill = !--fs->users; - write_unlock(&fs->lock); + spin_unlock(&fs->lock); task_unlock(tsk); if (kill) free_fs_struct(fs); @@ -104,7 +104,7 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old) if (fs) { fs->users = 1; fs->in_exec = 0; - rwlock_init(&fs->lock); + spin_lock_init(&fs->lock); fs->umask = old->umask; get_fs_root_and_pwd(old, &fs->root, &fs->pwd); } @@ -121,10 +121,10 @@ int unshare_fs_struct(void) return -ENOMEM; task_lock(current); - write_lock(&fs->lock); + spin_lock(&fs->lock); kill = !--fs->users; current->fs = new_fs; - write_unlock(&fs->lock); + spin_unlock(&fs->lock); task_unlock(current); if (kill) @@ -143,7 +143,7 @@ EXPORT_SYMBOL(current_umask); /* to be mentioned only in INIT_TASK */ struct fs_struct init_fs = { .users = 1, - .lock = __RW_LOCK_UNLOCKED(init_fs.lock), + .lock = __SPIN_LOCK_UNLOCKED(init_fs.lock), .umask = 0022, }; @@ -156,14 +156,14 @@ void daemonize_fs_struct(void) task_lock(current); - write_lock(&init_fs.lock); + spin_lock(&init_fs.lock); init_fs.users++; - write_unlock(&init_fs.lock); + spin_unlock(&init_fs.lock); - write_lock(&fs->lock); + spin_lock(&fs->lock); current->fs = &init_fs; kill = !--fs->users; - write_unlock(&fs->lock); + spin_unlock(&fs->lock); task_unlock(current); if (kill) diff --git a/include/linux/fs_struct.h b/include/linux/fs_struct.h index eca3d52..a42b5bf 100644 --- a/include/linux/fs_struct.h +++ b/include/linux/fs_struct.h @@ -5,7 +5,7 @@ struct fs_struct { int users; - rwlock_t lock; + spinlock_t lock; int umask; int in_exec; struct path root, pwd; @@ -23,29 +23,29 @@ extern int unshare_fs_struct(void); static inline void get_fs_root(struct fs_struct *fs, struct path *root) { - read_lock(&fs->lock); + spin_lock(&fs->lock); *root = fs->root; path_get(root); - read_unlock(&fs->lock); + spin_unlock(&fs->lock); } static inline void get_fs_pwd(struct fs_struct *fs, struct path *pwd) { - read_lock(&fs->lock); + spin_lock(&fs->lock); *pwd = fs->pwd; path_get(pwd); - read_unlock(&fs->lock); + spin_unlock(&fs->lock); } static inline void get_fs_root_and_pwd(struct fs_struct *fs, struct path *root, struct path *pwd) { - read_lock(&fs->lock); + spin_lock(&fs->lock); *root = fs->root; path_get(root); *pwd = fs->pwd; path_get(pwd); - read_unlock(&fs->lock); + spin_unlock(&fs->lock); } #endif /* _LINUX_FS_STRUCT_H */ diff --git a/kernel/fork.c b/kernel/fork.c index 98b4508..856eac3 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -752,13 +752,13 @@ static int copy_fs(unsigned long clone_flags, struct task_struct *tsk) struct fs_struct *fs = current->fs; if (clone_flags & CLONE_FS) { /* tsk->fs is already what we want */ - write_lock(&fs->lock); + spin_lock(&fs->lock); if (fs->in_exec) { - write_unlock(&fs->lock); + spin_unlock(&fs->lock); return -EAGAIN; } fs->users++; - write_unlock(&fs->lock); + spin_unlock(&fs->lock); return 0; } tsk->fs = copy_fs_struct(fs); @@ -1676,13 +1676,13 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags) if (new_fs) { fs = current->fs; - write_lock(&fs->lock); + spin_lock(&fs->lock); current->fs = new_fs; if (--fs->users) new_fs = NULL; else new_fs = fs; - write_unlock(&fs->lock); + spin_unlock(&fs->lock); } if (new_mm) { -- cgit v0.10.2 From b04f784e5d19ed58892833dae845738972cea260 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 18 Aug 2010 04:37:34 +1000 Subject: fs: remove extra lookup in __lookup_hash fs: remove extra lookup in __lookup_hash Optimize lookup for create operations, where no dentry should often be common-case. In cases where it is not, such as unlink, the added overhead is much smaller than the removed. Also, move comments about __d_lookup racyness to the __d_lookup call site. d_lookup is intuitive; __d_lookup is what needs commenting. So in that same vein, add kerneldoc comments to __d_lookup and clean up some of the comments: - We are interested in how the RCU lookup works here, particularly with renames. Make that explicit, and point to the document where it is explained in more detail. - RCU is pretty standard now, and macros make implementations pretty mindless. If we want to know about RCU barrier details, we look in RCU code. - Delete some boring legacy comments because we don't care much about how the code used to work, more about the interesting parts of how it works now. So comments about lazy LRU may be interesting, but would better be done in the LRU or refcount management code. Signed-off-by: Nick Piggin Signed-off-by: Al Viro diff --git a/fs/dcache.c b/fs/dcache.c index 4d13bf5..d56a40b 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1332,31 +1332,13 @@ EXPORT_SYMBOL(d_add_ci); * d_lookup - search for a dentry * @parent: parent dentry * @name: qstr of name we wish to find + * Returns: dentry, or NULL * - * Searches the children of the parent dentry for the name in question. If - * the dentry is found its reference count is incremented and the dentry - * is returned. The caller must use dput to free the entry when it has - * finished using it. %NULL is returned on failure. - * - * __d_lookup is dcache_lock free. The hash list is protected using RCU. - * Memory barriers are used while updating and doing lockless traversal. - * To avoid races with d_move while rename is happening, d_lock is used. - * - * Overflows in memcmp(), while d_move, are avoided by keeping the length - * and name pointer in one structure pointed by d_qstr. - * - * rcu_read_lock() and rcu_read_unlock() are used to disable preemption while - * lookup is going on. - * - * The dentry unused LRU is not updated even if lookup finds the required dentry - * in there. It is updated in places such as prune_dcache, shrink_dcache_sb, - * select_parent and __dget_locked. This laziness saves lookup from dcache_lock - * acquisition. - * - * d_lookup() is protected against the concurrent renames in some unrelated - * directory using the seqlockt_t rename_lock. + * d_lookup searches the children of the parent dentry for the name in + * question. If the dentry is found its reference count is incremented and the + * dentry is returned. The caller must use dput to free the entry when it has + * finished using it. %NULL is returned if the dentry does not exist. */ - struct dentry * d_lookup(struct dentry * parent, struct qstr * name) { struct dentry * dentry = NULL; @@ -1372,6 +1354,21 @@ struct dentry * d_lookup(struct dentry * parent, struct qstr * name) } EXPORT_SYMBOL(d_lookup); +/* + * __d_lookup - search for a dentry (racy) + * @parent: parent dentry + * @name: qstr of name we wish to find + * Returns: dentry, or NULL + * + * __d_lookup is like d_lookup, however it may (rarely) return a + * false-negative result due to unrelated rename activity. + * + * __d_lookup is slightly faster by avoiding rename_lock read seqlock, + * however it must be used carefully, eg. with a following d_lookup in + * the case of failure. + * + * __d_lookup callers must be commented. + */ struct dentry * __d_lookup(struct dentry * parent, struct qstr * name) { unsigned int len = name->len; @@ -1382,6 +1379,19 @@ struct dentry * __d_lookup(struct dentry * parent, struct qstr * name) struct hlist_node *node; struct dentry *dentry; + /* + * The hash list is protected using RCU. + * + * Take d_lock when comparing a candidate dentry, to avoid races + * with d_move(). + * + * It is possible that concurrent renames can mess up our list + * walk here and result in missing our dentry, resulting in the + * false-negative result. d_lookup() protects against concurrent + * renames using rename_lock seqlock. + * + * See Documentation/vfs/dcache-locking.txt for more details. + */ rcu_read_lock(); hlist_for_each_entry_rcu(dentry, node, head, d_hash) { @@ -1396,8 +1406,8 @@ struct dentry * __d_lookup(struct dentry * parent, struct qstr * name) /* * Recheck the dentry after taking the lock - d_move may have - * changed things. Don't bother checking the hash because we're - * about to compare the whole name anyway. + * changed things. Don't bother checking the hash because + * we're about to compare the whole name anyway. */ if (dentry->d_parent != parent) goto next; diff --git a/fs/namei.c b/fs/namei.c index b815a4d..11de7c3 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -735,6 +735,11 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, return err; } + /* + * Rename seqlock is not required here because in the off chance + * of a false negative due to a concurrent rename, we're going to + * do the non-racy lookup, below. + */ dentry = __d_lookup(nd->path.dentry, name); if (!dentry) goto need_lookup; @@ -754,17 +759,13 @@ need_lookup: mutex_lock(&dir->i_mutex); /* * First re-do the cached lookup just in case it was created - * while we waited for the directory semaphore.. - * - * FIXME! This could use version numbering or similar to - * avoid unnecessary cache lookups. - * - * The "dcache_lock" is purely to protect the RCU list walker - * from concurrent renames at this point (we mustn't get false - * negatives from the RCU list walk here, unlike the optimistic - * fast walk). + * while we waited for the directory semaphore, or the first + * lookup failed due to an unrelated rename. * - * so doing d_lookup() (with seqlock), instead of lockfree __d_lookup + * This could use version numbering or similar to avoid unnecessary + * cache lookups, but then we'd have to do the first lookup in the + * non-racy way. However in the common case here, everything should + * be hot in cache, so would it be a big win? */ dentry = d_lookup(parent, name); if (likely(!dentry)) { @@ -1136,13 +1137,12 @@ static struct dentry *__lookup_hash(struct qstr *name, goto out; } - dentry = __d_lookup(base, name); - - /* lockess __d_lookup may fail due to concurrent d_move() - * in some unrelated directory, so try with d_lookup + /* + * Don't bother with __d_lookup: callers are for creat as + * well as unlink, so a lot of the time it would cost + * a double lookup. */ - if (!dentry) - dentry = d_lookup(base, name); + dentry = d_lookup(base, name); if (dentry && dentry->d_op && dentry->d_op->d_revalidate) dentry = do_revalidate(dentry, nd); -- cgit v0.10.2 From ee2ffa0dfdd2db19705f2ba1c6a4c0bfe8122dd8 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 18 Aug 2010 04:37:35 +1000 Subject: fs: cleanup files_lock locking fs: cleanup files_lock locking Lock tty_files with a new spinlock, tty_files_lock; provide helpers to manipulate the per-sb files list; unexport the files_lock spinlock. Cc: linux-kernel@vger.kernel.org Cc: Christoph Hellwig Cc: Alan Cox Acked-by: Andi Kleen Acked-by: Greg Kroah-Hartman Signed-off-by: Nick Piggin Signed-off-by: Al Viro diff --git a/drivers/char/pty.c b/drivers/char/pty.c index ad46eae..2c64faa 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -676,7 +676,11 @@ static int ptmx_open(struct inode *inode, struct file *filp) set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ filp->private_data = tty; - file_move(filp, &tty->tty_files); + + file_sb_list_del(filp); /* __dentry_open has put it on the sb list */ + spin_lock(&tty_files_lock); + list_add(&filp->f_u.fu_list, &tty->tty_files); + spin_unlock(&tty_files_lock); retval = devpts_pty_new(inode, tty->link); if (retval) diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 0350c42..cd5b829 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -136,6 +136,9 @@ LIST_HEAD(tty_drivers); /* linked list of tty drivers */ DEFINE_MUTEX(tty_mutex); EXPORT_SYMBOL(tty_mutex); +/* Spinlock to protect the tty->tty_files list */ +DEFINE_SPINLOCK(tty_files_lock); + static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *); static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *); ssize_t redirected_tty_write(struct file *, const char __user *, @@ -235,11 +238,11 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) struct list_head *p; int count = 0; - file_list_lock(); + spin_lock(&tty_files_lock); list_for_each(p, &tty->tty_files) { count++; } - file_list_unlock(); + spin_unlock(&tty_files_lock); if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_SLAVE && tty->link && tty->link->count) @@ -519,7 +522,7 @@ void __tty_hangup(struct tty_struct *tty) workqueue with the lock held */ check_tty_count(tty, "tty_hangup"); - file_list_lock(); + spin_lock(&tty_files_lock); /* This breaks for file handles being sent over AF_UNIX sockets ? */ list_for_each_entry(filp, &tty->tty_files, f_u.fu_list) { if (filp->f_op->write == redirected_tty_write) @@ -530,7 +533,7 @@ void __tty_hangup(struct tty_struct *tty) __tty_fasync(-1, filp, 0); /* can't block */ filp->f_op = &hung_up_tty_fops; } - file_list_unlock(); + spin_unlock(&tty_files_lock); tty_ldisc_hangup(tty); @@ -1424,9 +1427,9 @@ static void release_one_tty(struct work_struct *work) tty_driver_kref_put(driver); module_put(driver->owner); - file_list_lock(); + spin_lock(&tty_files_lock); list_del_init(&tty->tty_files); - file_list_unlock(); + spin_unlock(&tty_files_lock); put_pid(tty->pgrp); put_pid(tty->session); @@ -1671,7 +1674,10 @@ int tty_release(struct inode *inode, struct file *filp) * - do_tty_hangup no longer sees this file descriptor as * something that needs to be handled for hangups. */ - file_kill(filp); + spin_lock(&tty_files_lock); + BUG_ON(list_empty(&filp->f_u.fu_list)); + list_del_init(&filp->f_u.fu_list); + spin_unlock(&tty_files_lock); filp->private_data = NULL; /* @@ -1840,7 +1846,11 @@ got_driver: } filp->private_data = tty; - file_move(filp, &tty->tty_files); + BUG_ON(list_empty(&filp->f_u.fu_list)); + file_sb_list_del(filp); /* __dentry_open has put it on the sb list */ + spin_lock(&tty_files_lock); + list_add(&filp->f_u.fu_list, &tty->tty_files); + spin_unlock(&tty_files_lock); check_tty_count(tty, "tty_open"); if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER) diff --git a/fs/file_table.c b/fs/file_table.c index edecd36..6f0e62e 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -32,8 +32,7 @@ struct files_stat_struct files_stat = { .max_files = NR_FILE }; -/* public. Not pretty! */ -__cacheline_aligned_in_smp DEFINE_SPINLOCK(files_lock); +static __cacheline_aligned_in_smp DEFINE_SPINLOCK(files_lock); /* SLAB cache for file structures */ static struct kmem_cache *filp_cachep __read_mostly; @@ -249,7 +248,7 @@ static void __fput(struct file *file) cdev_put(inode->i_cdev); fops_put(file->f_op); put_pid(file->f_owner.pid); - file_kill(file); + file_sb_list_del(file); if (file->f_mode & FMODE_WRITE) drop_file_write_access(file); file->f_path.dentry = NULL; @@ -328,31 +327,29 @@ struct file *fget_light(unsigned int fd, int *fput_needed) return file; } - void put_filp(struct file *file) { if (atomic_long_dec_and_test(&file->f_count)) { security_file_free(file); - file_kill(file); + file_sb_list_del(file); file_free(file); } } -void file_move(struct file *file, struct list_head *list) +void file_sb_list_add(struct file *file, struct super_block *sb) { - if (!list) - return; - file_list_lock(); - list_move(&file->f_u.fu_list, list); - file_list_unlock(); + spin_lock(&files_lock); + BUG_ON(!list_empty(&file->f_u.fu_list)); + list_add(&file->f_u.fu_list, &sb->s_files); + spin_unlock(&files_lock); } -void file_kill(struct file *file) +void file_sb_list_del(struct file *file) { if (!list_empty(&file->f_u.fu_list)) { - file_list_lock(); + spin_lock(&files_lock); list_del_init(&file->f_u.fu_list); - file_list_unlock(); + spin_unlock(&files_lock); } } @@ -361,7 +358,7 @@ int fs_may_remount_ro(struct super_block *sb) struct file *file; /* Check that no files are currently opened for writing. */ - file_list_lock(); + spin_lock(&files_lock); list_for_each_entry(file, &sb->s_files, f_u.fu_list) { struct inode *inode = file->f_path.dentry->d_inode; @@ -373,10 +370,10 @@ int fs_may_remount_ro(struct super_block *sb) if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE)) goto too_bad; } - file_list_unlock(); + spin_unlock(&files_lock); return 1; /* Tis' cool bro. */ too_bad: - file_list_unlock(); + spin_unlock(&files_lock); return 0; } @@ -392,7 +389,7 @@ void mark_files_ro(struct super_block *sb) struct file *f; retry: - file_list_lock(); + spin_lock(&files_lock); list_for_each_entry(f, &sb->s_files, f_u.fu_list) { struct vfsmount *mnt; if (!S_ISREG(f->f_path.dentry->d_inode->i_mode)) @@ -408,16 +405,13 @@ retry: continue; file_release_write(f); mnt = mntget(f->f_path.mnt); - file_list_unlock(); - /* - * This can sleep, so we can't hold - * the file_list_lock() spinlock. - */ + /* This can sleep, so we can't hold the spinlock. */ + spin_unlock(&files_lock); mnt_drop_write(mnt); mntput(mnt); goto retry; } - file_list_unlock(); + spin_unlock(&files_lock); } void __init files_init(unsigned long mempages) diff --git a/fs/open.c b/fs/open.c index 630715f..d74e198 100644 --- a/fs/open.c +++ b/fs/open.c @@ -675,7 +675,7 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, f->f_path.mnt = mnt; f->f_pos = 0; f->f_op = fops_get(inode->i_fop); - file_move(f, &inode->i_sb->s_files); + file_sb_list_add(f, inode->i_sb); error = security_dentry_open(f, cred); if (error) @@ -721,7 +721,7 @@ cleanup_all: mnt_drop_write(mnt); } } - file_kill(f); + file_sb_list_del(f); f->f_path.dentry = NULL; f->f_path.mnt = NULL; cleanup_file: diff --git a/include/linux/fs.h b/include/linux/fs.h index 29f7c97..5a9a9e5 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -944,9 +944,6 @@ struct file { unsigned long f_mnt_write_state; #endif }; -extern spinlock_t files_lock; -#define file_list_lock() spin_lock(&files_lock); -#define file_list_unlock() spin_unlock(&files_lock); #define get_file(x) atomic_long_inc(&(x)->f_count) #define fput_atomic(x) atomic_long_add_unless(&(x)->f_count, -1, 1) @@ -2188,8 +2185,8 @@ static inline void insert_inode_hash(struct inode *inode) { __insert_inode_hash(inode, inode->i_ino); } -extern void file_move(struct file *f, struct list_head *list); -extern void file_kill(struct file *f); +extern void file_sb_list_add(struct file *f, struct super_block *sb); +extern void file_sb_list_del(struct file *f); #ifdef CONFIG_BLOCK extern void submit_bio(int, struct bio *); extern int bdev_read_only(struct block_device *); diff --git a/include/linux/tty.h b/include/linux/tty.h index 1437da3..f6b371a 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -470,6 +470,7 @@ extern struct tty_struct *tty_pair_get_tty(struct tty_struct *tty); extern struct tty_struct *tty_pair_get_pty(struct tty_struct *tty); extern struct mutex tty_mutex; +extern spinlock_t tty_files_lock; extern void tty_write_unlock(struct tty_struct *tty); extern int tty_write_lock(struct tty_struct *tty, int ndelay); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 42043f9..bd7da0f 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2170,7 +2170,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, tty = get_current_tty(); if (tty) { - file_list_lock(); + spin_lock(&tty_files_lock); if (!list_empty(&tty->tty_files)) { struct inode *inode; @@ -2186,7 +2186,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, drop_tty = 1; } } - file_list_unlock(); + spin_unlock(&tty_files_lock); tty_kref_put(tty); } /* Reset controlling tty. */ -- cgit v0.10.2 From d996b62a8df1d935b01319bf8defb95b5709f7b8 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 18 Aug 2010 04:37:36 +1000 Subject: tty: fix fu_list abuse tty: fix fu_list abuse tty code abuses fu_list, which causes a bug in remount,ro handling. If a tty device node is opened on a filesystem, then the last link to the inode removed, the filesystem will be allowed to be remounted readonly. This is because fs_may_remount_ro does not find the 0 link tty inode on the file sb list (because the tty code incorrectly removed it to use for its own purpose). This can result in a filesystem with errors after it is marked "clean". Taking idea from Christoph's initial patch, allocate a tty private struct at file->private_data and put our required list fields in there, linking file and tty. This makes tty nodes behave the same way as other device nodes and avoid meddling with the vfs, and avoids this bug. The error handling is not trivial in the tty code, so for this bugfix, I take the simple approach of using __GFP_NOFAIL and don't worry about memory errors. This is not a problem because our allocator doesn't fail small allocs as a rule anyway. So proper error handling is left as an exercise for tty hackers. [ Arguably filesystem's device inode would ideally be divorced from the driver's pseudo inode when it is opened, but in practice it's not clear whether that will ever be worth implementing. ] Cc: linux-kernel@vger.kernel.org Cc: Christoph Hellwig Cc: Alan Cox Cc: Greg Kroah-Hartman Signed-off-by: Nick Piggin Signed-off-by: Al Viro diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 2c64faa..c350d01 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -675,12 +675,8 @@ static int ptmx_open(struct inode *inode, struct file *filp) } set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ - filp->private_data = tty; - file_sb_list_del(filp); /* __dentry_open has put it on the sb list */ - spin_lock(&tty_files_lock); - list_add(&filp->f_u.fu_list, &tty->tty_files); - spin_unlock(&tty_files_lock); + tty_add_file(tty, filp); retval = devpts_pty_new(inode, tty->link); if (retval) diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index cd5b829..949067a 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -188,6 +188,41 @@ void free_tty_struct(struct tty_struct *tty) kfree(tty); } +static inline struct tty_struct *file_tty(struct file *file) +{ + return ((struct tty_file_private *)file->private_data)->tty; +} + +/* Associate a new file with the tty structure */ +void tty_add_file(struct tty_struct *tty, struct file *file) +{ + struct tty_file_private *priv; + + /* XXX: must implement proper error handling in callers */ + priv = kmalloc(sizeof(*priv), GFP_KERNEL|__GFP_NOFAIL); + + priv->tty = tty; + priv->file = file; + file->private_data = priv; + + spin_lock(&tty_files_lock); + list_add(&priv->list, &tty->tty_files); + spin_unlock(&tty_files_lock); +} + +/* Delete file from its tty */ +void tty_del_file(struct file *file) +{ + struct tty_file_private *priv = file->private_data; + + spin_lock(&tty_files_lock); + list_del(&priv->list); + spin_unlock(&tty_files_lock); + file->private_data = NULL; + kfree(priv); +} + + #define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base) /** @@ -500,6 +535,7 @@ void __tty_hangup(struct tty_struct *tty) struct file *cons_filp = NULL; struct file *filp, *f = NULL; struct task_struct *p; + struct tty_file_private *priv; int closecount = 0, n; unsigned long flags; int refs = 0; @@ -509,7 +545,7 @@ void __tty_hangup(struct tty_struct *tty) spin_lock(&redirect_lock); - if (redirect && redirect->private_data == tty) { + if (redirect && file_tty(redirect) == tty) { f = redirect; redirect = NULL; } @@ -524,7 +560,8 @@ void __tty_hangup(struct tty_struct *tty) spin_lock(&tty_files_lock); /* This breaks for file handles being sent over AF_UNIX sockets ? */ - list_for_each_entry(filp, &tty->tty_files, f_u.fu_list) { + list_for_each_entry(priv, &tty->tty_files, list) { + filp = priv->file; if (filp->f_op->write == redirected_tty_write) cons_filp = filp; if (filp->f_op->write != tty_write) @@ -892,12 +929,10 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { int i; - struct tty_struct *tty; - struct inode *inode; + struct inode *inode = file->f_path.dentry->d_inode; + struct tty_struct *tty = file_tty(file); struct tty_ldisc *ld; - tty = file->private_data; - inode = file->f_path.dentry->d_inode; if (tty_paranoia_check(tty, inode, "tty_read")) return -EIO; if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags))) @@ -1068,12 +1103,11 @@ void tty_write_message(struct tty_struct *tty, char *msg) static ssize_t tty_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - struct tty_struct *tty; struct inode *inode = file->f_path.dentry->d_inode; + struct tty_struct *tty = file_tty(file); + struct tty_ldisc *ld; ssize_t ret; - struct tty_ldisc *ld; - tty = file->private_data; if (tty_paranoia_check(tty, inode, "tty_write")) return -EIO; if (!tty || !tty->ops->write || @@ -1510,13 +1544,13 @@ static void release_tty(struct tty_struct *tty, int idx) int tty_release(struct inode *inode, struct file *filp) { - struct tty_struct *tty, *o_tty; + struct tty_struct *tty = file_tty(filp); + struct tty_struct *o_tty; int pty_master, tty_closing, o_tty_closing, do_sleep; int devpts; int idx; char buf[64]; - tty = filp->private_data; if (tty_paranoia_check(tty, inode, "tty_release_dev")) return 0; @@ -1674,11 +1708,7 @@ int tty_release(struct inode *inode, struct file *filp) * - do_tty_hangup no longer sees this file descriptor as * something that needs to be handled for hangups. */ - spin_lock(&tty_files_lock); - BUG_ON(list_empty(&filp->f_u.fu_list)); - list_del_init(&filp->f_u.fu_list); - spin_unlock(&tty_files_lock); - filp->private_data = NULL; + tty_del_file(filp); /* * Perform some housekeeping before deciding whether to return. @@ -1845,12 +1875,8 @@ got_driver: return PTR_ERR(tty); } - filp->private_data = tty; - BUG_ON(list_empty(&filp->f_u.fu_list)); - file_sb_list_del(filp); /* __dentry_open has put it on the sb list */ - spin_lock(&tty_files_lock); - list_add(&filp->f_u.fu_list, &tty->tty_files); - spin_unlock(&tty_files_lock); + tty_add_file(tty, filp); + check_tty_count(tty, "tty_open"); if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER) @@ -1926,11 +1952,10 @@ got_driver: static unsigned int tty_poll(struct file *filp, poll_table *wait) { - struct tty_struct *tty; + struct tty_struct *tty = file_tty(filp); struct tty_ldisc *ld; int ret = 0; - tty = filp->private_data; if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_poll")) return 0; @@ -1943,11 +1968,10 @@ static unsigned int tty_poll(struct file *filp, poll_table *wait) static int __tty_fasync(int fd, struct file *filp, int on) { - struct tty_struct *tty; + struct tty_struct *tty = file_tty(filp); unsigned long flags; int retval = 0; - tty = filp->private_data; if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_fasync")) goto out; @@ -2501,13 +2525,13 @@ EXPORT_SYMBOL(tty_pair_get_pty); */ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct tty_struct *tty, *real_tty; + struct tty_struct *tty = file_tty(file); + struct tty_struct *real_tty; void __user *p = (void __user *)arg; int retval; struct tty_ldisc *ld; struct inode *inode = file->f_dentry->d_inode; - tty = file->private_data; if (tty_paranoia_check(tty, inode, "tty_ioctl")) return -EINVAL; @@ -2629,7 +2653,7 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct inode *inode = file->f_dentry->d_inode; - struct tty_struct *tty = file->private_data; + struct tty_struct *tty = file_tty(file); struct tty_ldisc *ld; int retval = -ENOIOCTLCMD; @@ -2721,7 +2745,7 @@ void __do_SAK(struct tty_struct *tty) if (!filp) continue; if (filp->f_op->read == tty_read && - filp->private_data == tty) { + file_tty(filp) == tty) { printk(KERN_NOTICE "SAK: killed process %d" " (%s): fd#%d opened to the tty\n", task_pid_nr(p), p->comm, i); diff --git a/fs/internal.h b/fs/internal.h index 6b706bc..6a5c13a8 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -80,6 +80,8 @@ extern void chroot_fs_refs(struct path *, struct path *); /* * file_table.c */ +extern void file_sb_list_add(struct file *f, struct super_block *sb); +extern void file_sb_list_del(struct file *f); extern void mark_files_ro(struct super_block *); extern struct file *get_empty_filp(void); diff --git a/include/linux/fs.h b/include/linux/fs.h index 5a9a9e5..5e65add 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2185,8 +2185,6 @@ static inline void insert_inode_hash(struct inode *inode) { __insert_inode_hash(inode, inode->i_ino); } -extern void file_sb_list_add(struct file *f, struct super_block *sb); -extern void file_sb_list_del(struct file *f); #ifdef CONFIG_BLOCK extern void submit_bio(int, struct bio *); extern int bdev_read_only(struct block_device *); diff --git a/include/linux/tty.h b/include/linux/tty.h index f6b371a..67d64e6 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -329,6 +329,13 @@ struct tty_struct { struct tty_port *port; }; +/* Each of a tty's open files has private_data pointing to tty_file_private */ +struct tty_file_private { + struct tty_struct *tty; + struct file *file; + struct list_head list; +}; + /* tty magic number */ #define TTY_MAGIC 0x5401 @@ -458,6 +465,7 @@ extern void proc_clear_tty(struct task_struct *p); extern struct tty_struct *get_current_tty(void); extern void tty_default_fops(struct file_operations *fops); extern struct tty_struct *alloc_tty_struct(void); +extern void tty_add_file(struct tty_struct *tty, struct file *file); extern void free_tty_struct(struct tty_struct *tty); extern void initialize_tty_struct(struct tty_struct *tty, struct tty_driver *driver, int idx); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index bd7da0f..4796ddd 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2172,6 +2172,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, if (tty) { spin_lock(&tty_files_lock); if (!list_empty(&tty->tty_files)) { + struct tty_file_private *file_priv; struct inode *inode; /* Revalidate access to controlling tty. @@ -2179,7 +2180,9 @@ static inline void flush_unauthorized_files(const struct cred *cred, than using file_has_perm, as this particular open file may belong to another process and we are only interested in the inode-based check here. */ - file = list_first_entry(&tty->tty_files, struct file, f_u.fu_list); + file_priv = list_first_entry(&tty->tty_files, + struct tty_file_private, list); + file = file_priv->file; inode = file->f_path.dentry->d_inode; if (inode_has_perm(cred, inode, FILE__READ | FILE__WRITE, NULL)) { -- cgit v0.10.2 From 2dc91abe03d8ce6dd7f9251faffafca5f6b9e85d Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 18 Aug 2010 04:37:37 +1000 Subject: lglock: introduce special lglock and brlock spin locks lglock: introduce special lglock and brlock spin locks This patch introduces "local-global" locks (lglocks). These can be used to: - Provide fast exclusive access to per-CPU data, with exclusive access to another CPU's data allowed but possibly subject to contention, and to provide very slow exclusive access to all per-CPU data. - Or to provide very fast and scalable read serialisation, and to provide very slow exclusive serialisation of data (not necessarily per-CPU data). Brlocks are also implemented as a short-hand notation for the latter use case. Thanks to Paul for local/global naming convention. Cc: linux-kernel@vger.kernel.org Cc: Al Viro Cc: "Paul E. McKenney" Signed-off-by: Nick Piggin Signed-off-by: Al Viro diff --git a/include/linux/lglock.h b/include/linux/lglock.h new file mode 100644 index 0000000..b288cb7 --- /dev/null +++ b/include/linux/lglock.h @@ -0,0 +1,172 @@ +/* + * Specialised local-global spinlock. Can only be declared as global variables + * to avoid overhead and keep things simple (and we don't want to start using + * these inside dynamically allocated structures). + * + * "local/global locks" (lglocks) can be used to: + * + * - Provide fast exclusive access to per-CPU data, with exclusive access to + * another CPU's data allowed but possibly subject to contention, and to + * provide very slow exclusive access to all per-CPU data. + * - Or to provide very fast and scalable read serialisation, and to provide + * very slow exclusive serialisation of data (not necessarily per-CPU data). + * + * Brlocks are also implemented as a short-hand notation for the latter use + * case. + * + * Copyright 2009, 2010, Nick Piggin, Novell Inc. + */ +#ifndef __LINUX_LGLOCK_H +#define __LINUX_LGLOCK_H + +#include +#include +#include + +/* can make br locks by using local lock for read side, global lock for write */ +#define br_lock_init(name) name##_lock_init() +#define br_read_lock(name) name##_local_lock() +#define br_read_unlock(name) name##_local_unlock() +#define br_write_lock(name) name##_global_lock_online() +#define br_write_unlock(name) name##_global_unlock_online() + +#define DECLARE_BRLOCK(name) DECLARE_LGLOCK(name) +#define DEFINE_BRLOCK(name) DEFINE_LGLOCK(name) + + +#define lg_lock_init(name) name##_lock_init() +#define lg_local_lock(name) name##_local_lock() +#define lg_local_unlock(name) name##_local_unlock() +#define lg_local_lock_cpu(name, cpu) name##_local_lock_cpu(cpu) +#define lg_local_unlock_cpu(name, cpu) name##_local_unlock_cpu(cpu) +#define lg_global_lock(name) name##_global_lock() +#define lg_global_unlock(name) name##_global_unlock() +#define lg_global_lock_online(name) name##_global_lock_online() +#define lg_global_unlock_online(name) name##_global_unlock_online() + +#ifdef CONFIG_DEBUG_LOCK_ALLOC +#define LOCKDEP_INIT_MAP lockdep_init_map + +#define DEFINE_LGLOCK_LOCKDEP(name) \ + struct lock_class_key name##_lock_key; \ + struct lockdep_map name##_lock_dep_map; \ + EXPORT_SYMBOL(name##_lock_dep_map) + +#else +#define LOCKDEP_INIT_MAP(a, b, c, d) + +#define DEFINE_LGLOCK_LOCKDEP(name) +#endif + + +#define DECLARE_LGLOCK(name) \ + extern void name##_lock_init(void); \ + extern void name##_local_lock(void); \ + extern void name##_local_unlock(void); \ + extern void name##_local_lock_cpu(int cpu); \ + extern void name##_local_unlock_cpu(int cpu); \ + extern void name##_global_lock(void); \ + extern void name##_global_unlock(void); \ + extern void name##_global_lock_online(void); \ + extern void name##_global_unlock_online(void); \ + +#define DEFINE_LGLOCK(name) \ + \ + DEFINE_PER_CPU(arch_spinlock_t, name##_lock); \ + DEFINE_LGLOCK_LOCKDEP(name); \ + \ + void name##_lock_init(void) { \ + int i; \ + LOCKDEP_INIT_MAP(&name##_lock_dep_map, #name, &name##_lock_key, 0); \ + for_each_possible_cpu(i) { \ + arch_spinlock_t *lock; \ + lock = &per_cpu(name##_lock, i); \ + *lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; \ + } \ + } \ + EXPORT_SYMBOL(name##_lock_init); \ + \ + void name##_local_lock(void) { \ + arch_spinlock_t *lock; \ + preempt_disable(); \ + rwlock_acquire_read(&name##_lock_dep_map, 0, 0, _THIS_IP_); \ + lock = &__get_cpu_var(name##_lock); \ + arch_spin_lock(lock); \ + } \ + EXPORT_SYMBOL(name##_local_lock); \ + \ + void name##_local_unlock(void) { \ + arch_spinlock_t *lock; \ + rwlock_release(&name##_lock_dep_map, 1, _THIS_IP_); \ + lock = &__get_cpu_var(name##_lock); \ + arch_spin_unlock(lock); \ + preempt_enable(); \ + } \ + EXPORT_SYMBOL(name##_local_unlock); \ + \ + void name##_local_lock_cpu(int cpu) { \ + arch_spinlock_t *lock; \ + preempt_disable(); \ + rwlock_acquire_read(&name##_lock_dep_map, 0, 0, _THIS_IP_); \ + lock = &per_cpu(name##_lock, cpu); \ + arch_spin_lock(lock); \ + } \ + EXPORT_SYMBOL(name##_local_lock_cpu); \ + \ + void name##_local_unlock_cpu(int cpu) { \ + arch_spinlock_t *lock; \ + rwlock_release(&name##_lock_dep_map, 1, _THIS_IP_); \ + lock = &per_cpu(name##_lock, cpu); \ + arch_spin_unlock(lock); \ + preempt_enable(); \ + } \ + EXPORT_SYMBOL(name##_local_unlock_cpu); \ + \ + void name##_global_lock_online(void) { \ + int i; \ + preempt_disable(); \ + rwlock_acquire(&name##_lock_dep_map, 0, 0, _RET_IP_); \ + for_each_online_cpu(i) { \ + arch_spinlock_t *lock; \ + lock = &per_cpu(name##_lock, i); \ + arch_spin_lock(lock); \ + } \ + } \ + EXPORT_SYMBOL(name##_global_lock_online); \ + \ + void name##_global_unlock_online(void) { \ + int i; \ + rwlock_release(&name##_lock_dep_map, 1, _RET_IP_); \ + for_each_online_cpu(i) { \ + arch_spinlock_t *lock; \ + lock = &per_cpu(name##_lock, i); \ + arch_spin_unlock(lock); \ + } \ + preempt_enable(); \ + } \ + EXPORT_SYMBOL(name##_global_unlock_online); \ + \ + void name##_global_lock(void) { \ + int i; \ + preempt_disable(); \ + rwlock_acquire(&name##_lock_dep_map, 0, 0, _RET_IP_); \ + for_each_online_cpu(i) { \ + arch_spinlock_t *lock; \ + lock = &per_cpu(name##_lock, i); \ + arch_spin_lock(lock); \ + } \ + } \ + EXPORT_SYMBOL(name##_global_lock); \ + \ + void name##_global_unlock(void) { \ + int i; \ + rwlock_release(&name##_lock_dep_map, 1, _RET_IP_); \ + for_each_online_cpu(i) { \ + arch_spinlock_t *lock; \ + lock = &per_cpu(name##_lock, i); \ + arch_spin_unlock(lock); \ + } \ + preempt_enable(); \ + } \ + EXPORT_SYMBOL(name##_global_unlock); +#endif -- cgit v0.10.2 From 6416ccb7899960868f5016751fb81bf25213d24f Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 18 Aug 2010 04:37:38 +1000 Subject: fs: scale files_lock fs: scale files_lock Improve scalability of files_lock by adding per-cpu, per-sb files lists, protected with an lglock. The lglock provides fast access to the per-cpu lists to add and remove files. It also provides a snapshot of all the per-cpu lists (although this is very slow). One difficulty with this approach is that a file can be removed from the list by another CPU. We must track which per-cpu list the file is on with a new variale in the file struct (packed into a hole on 64-bit archs). Scalability could suffer if files are frequently removed from different cpu's list. However loads with frequent removal of files imply short interval between adding and removing the files, and the scheduler attempts to avoid moving processes too far away. Also, even in the case of cross-CPU removal, the hardware has much more opportunity to parallelise cacheline transfers with N cachelines than with 1. A worst-case test of 1 CPU allocating files subsequently being freed by N CPUs degenerates to contending on a single lock, which is no worse than before. When more than one CPU are allocating files, even if they are always freed by different CPUs, there will be more parallelism than the single-lock case. Testing results: On a 2 socket, 8 core opteron, I measure the number of times the lock is taken to remove the file, the number of times it is removed by the same CPU that added it, and the number of times it is removed by the same node that added it. Booting: locks= 25049 cpu-hits= 23174 (92.5%) node-hits= 23945 (95.6%) kbuild -j16 locks=2281913 cpu-hits=2208126 (96.8%) node-hits=2252674 (98.7%) dbench 64 locks=4306582 cpu-hits=4287247 (99.6%) node-hits=4299527 (99.8%) So a file is removed from the same CPU it was added by over 90% of the time. It remains within the same node 95% of the time. Tim Chen ran some numbers for a 64 thread Nehalem system performing a compile. throughput 2.6.34-rc2 24.5 +patch 24.9 us sys idle IO wait (in %) 2.6.34-rc2 51.25 28.25 17.25 3.25 +patch 53.75 18.5 19 8.75 So significantly less CPU time spent in kernel code, higher idle time and slightly higher throughput. Single threaded performance difference was within the noise of microbenchmarks. That is not to say penalty does not exist, the code is larger and more memory accesses required so it will be slightly slower. Cc: linux-kernel@vger.kernel.org Cc: Tim Chen Cc: Andi Kleen Signed-off-by: Nick Piggin Signed-off-by: Al Viro diff --git a/fs/file_table.c b/fs/file_table.c index 6f0e62e..a04bdd8 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -20,7 +20,9 @@ #include #include #include +#include #include +#include #include #include @@ -32,7 +34,8 @@ struct files_stat_struct files_stat = { .max_files = NR_FILE }; -static __cacheline_aligned_in_smp DEFINE_SPINLOCK(files_lock); +DECLARE_LGLOCK(files_lglock); +DEFINE_LGLOCK(files_lglock); /* SLAB cache for file structures */ static struct kmem_cache *filp_cachep __read_mostly; @@ -336,30 +339,98 @@ void put_filp(struct file *file) } } +static inline int file_list_cpu(struct file *file) +{ +#ifdef CONFIG_SMP + return file->f_sb_list_cpu; +#else + return smp_processor_id(); +#endif +} + +/* helper for file_sb_list_add to reduce ifdefs */ +static inline void __file_sb_list_add(struct file *file, struct super_block *sb) +{ + struct list_head *list; +#ifdef CONFIG_SMP + int cpu; + cpu = smp_processor_id(); + file->f_sb_list_cpu = cpu; + list = per_cpu_ptr(sb->s_files, cpu); +#else + list = &sb->s_files; +#endif + list_add(&file->f_u.fu_list, list); +} + +/** + * file_sb_list_add - add a file to the sb's file list + * @file: file to add + * @sb: sb to add it to + * + * Use this function to associate a file with the superblock of the inode it + * refers to. + */ void file_sb_list_add(struct file *file, struct super_block *sb) { - spin_lock(&files_lock); - BUG_ON(!list_empty(&file->f_u.fu_list)); - list_add(&file->f_u.fu_list, &sb->s_files); - spin_unlock(&files_lock); + lg_local_lock(files_lglock); + __file_sb_list_add(file, sb); + lg_local_unlock(files_lglock); } +/** + * file_sb_list_del - remove a file from the sb's file list + * @file: file to remove + * @sb: sb to remove it from + * + * Use this function to remove a file from its superblock. + */ void file_sb_list_del(struct file *file) { if (!list_empty(&file->f_u.fu_list)) { - spin_lock(&files_lock); + lg_local_lock_cpu(files_lglock, file_list_cpu(file)); list_del_init(&file->f_u.fu_list); - spin_unlock(&files_lock); + lg_local_unlock_cpu(files_lglock, file_list_cpu(file)); } } +#ifdef CONFIG_SMP + +/* + * These macros iterate all files on all CPUs for a given superblock. + * files_lglock must be held globally. + */ +#define do_file_list_for_each_entry(__sb, __file) \ +{ \ + int i; \ + for_each_possible_cpu(i) { \ + struct list_head *list; \ + list = per_cpu_ptr((__sb)->s_files, i); \ + list_for_each_entry((__file), list, f_u.fu_list) + +#define while_file_list_for_each_entry \ + } \ +} + +#else + +#define do_file_list_for_each_entry(__sb, __file) \ +{ \ + struct list_head *list; \ + list = &(sb)->s_files; \ + list_for_each_entry((__file), list, f_u.fu_list) + +#define while_file_list_for_each_entry \ +} + +#endif + int fs_may_remount_ro(struct super_block *sb) { struct file *file; - /* Check that no files are currently opened for writing. */ - spin_lock(&files_lock); - list_for_each_entry(file, &sb->s_files, f_u.fu_list) { + lg_global_lock(files_lglock); + do_file_list_for_each_entry(sb, file) { struct inode *inode = file->f_path.dentry->d_inode; /* File with pending delete? */ @@ -369,11 +440,11 @@ int fs_may_remount_ro(struct super_block *sb) /* Writeable file? */ if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE)) goto too_bad; - } - spin_unlock(&files_lock); + } while_file_list_for_each_entry; + lg_global_unlock(files_lglock); return 1; /* Tis' cool bro. */ too_bad: - spin_unlock(&files_lock); + lg_global_unlock(files_lglock); return 0; } @@ -389,8 +460,8 @@ void mark_files_ro(struct super_block *sb) struct file *f; retry: - spin_lock(&files_lock); - list_for_each_entry(f, &sb->s_files, f_u.fu_list) { + lg_global_lock(files_lglock); + do_file_list_for_each_entry(sb, f) { struct vfsmount *mnt; if (!S_ISREG(f->f_path.dentry->d_inode->i_mode)) continue; @@ -406,12 +477,12 @@ retry: file_release_write(f); mnt = mntget(f->f_path.mnt); /* This can sleep, so we can't hold the spinlock. */ - spin_unlock(&files_lock); + lg_global_unlock(files_lglock); mnt_drop_write(mnt); mntput(mnt); goto retry; - } - spin_unlock(&files_lock); + } while_file_list_for_each_entry; + lg_global_unlock(files_lglock); } void __init files_init(unsigned long mempages) @@ -431,5 +502,6 @@ void __init files_init(unsigned long mempages) if (files_stat.max_files < NR_FILE) files_stat.max_files = NR_FILE; files_defer_init(); + lg_lock_init(files_lglock); percpu_counter_init(&nr_files, 0); } diff --git a/fs/super.c b/fs/super.c index 9674ab2..8819e3a 100644 --- a/fs/super.c +++ b/fs/super.c @@ -54,7 +54,22 @@ static struct super_block *alloc_super(struct file_system_type *type) s = NULL; goto out; } +#ifdef CONFIG_SMP + s->s_files = alloc_percpu(struct list_head); + if (!s->s_files) { + security_sb_free(s); + kfree(s); + s = NULL; + goto out; + } else { + int i; + + for_each_possible_cpu(i) + INIT_LIST_HEAD(per_cpu_ptr(s->s_files, i)); + } +#else INIT_LIST_HEAD(&s->s_files); +#endif INIT_LIST_HEAD(&s->s_instances); INIT_HLIST_HEAD(&s->s_anon); INIT_LIST_HEAD(&s->s_inodes); @@ -108,6 +123,9 @@ out: */ static inline void destroy_super(struct super_block *s) { +#ifdef CONFIG_SMP + free_percpu(s->s_files); +#endif security_sb_free(s); kfree(s->s_subtype); kfree(s->s_options); diff --git a/include/linux/fs.h b/include/linux/fs.h index 5e65add..76041b6 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -920,6 +920,9 @@ struct file { #define f_vfsmnt f_path.mnt const struct file_operations *f_op; spinlock_t f_lock; /* f_ep_links, f_flags, no IRQ */ +#ifdef CONFIG_SMP + int f_sb_list_cpu; +#endif atomic_long_t f_count; unsigned int f_flags; fmode_t f_mode; @@ -1334,7 +1337,11 @@ struct super_block { struct list_head s_inodes; /* all inodes */ struct hlist_head s_anon; /* anonymous dentries for (nfs) exporting */ +#ifdef CONFIG_SMP + struct list_head __percpu *s_files; +#else struct list_head s_files; +#endif /* s_dentry_lru and s_nr_dentry_unused are protected by dcache_lock */ struct list_head s_dentry_lru; /* unused dentry lru */ int s_nr_dentry_unused; /* # of dentry on lru */ -- cgit v0.10.2 From 99b7db7b8ffd6bb755eb0a175596421a0b581cb2 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 18 Aug 2010 04:37:39 +1000 Subject: fs: brlock vfsmount_lock fs: brlock vfsmount_lock Use a brlock for the vfsmount lock. It must be taken for write whenever modifying the mount hash or associated fields, and may be taken for read when performing mount hash lookups. A new lock is added for the mnt-id allocator, so it doesn't need to take the heavy vfsmount write-lock. The number of atomics should remain the same for fastpath rlock cases, though code would be slightly slower due to per-cpu access. Scalability is not not be much improved in common cases yet, due to other locks (ie. dcache_lock) getting in the way. However path lookups crossing mountpoints should be one case where scalability is improved (currently requiring the global lock). The slowpath is slower due to use of brlock. On a 64 core, 64 socket, 32 node Altix system (high latency to remote nodes), a simple umount microbenchmark (mount --bind mnt mnt2 ; umount mnt2 loop 1000 times), before this patch it took 6.8s, afterwards took 7.1s, about 5% slower. Cc: Al Viro Signed-off-by: Nick Piggin Signed-off-by: Al Viro diff --git a/fs/dcache.c b/fs/dcache.c index d56a40b..83293be 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1935,7 +1935,7 @@ static int prepend_path(const struct path *path, struct path *root, bool slash = false; int error = 0; - spin_lock(&vfsmount_lock); + br_read_lock(vfsmount_lock); while (dentry != root->dentry || vfsmnt != root->mnt) { struct dentry * parent; @@ -1964,7 +1964,7 @@ out: if (!error && !slash) error = prepend(buffer, buflen, "/", 1); - spin_unlock(&vfsmount_lock); + br_read_unlock(vfsmount_lock); return error; global_root: @@ -2302,11 +2302,12 @@ int path_is_under(struct path *path1, struct path *path2) struct vfsmount *mnt = path1->mnt; struct dentry *dentry = path1->dentry; int res; - spin_lock(&vfsmount_lock); + + br_read_lock(vfsmount_lock); if (mnt != path2->mnt) { for (;;) { if (mnt->mnt_parent == mnt) { - spin_unlock(&vfsmount_lock); + br_read_unlock(vfsmount_lock); return 0; } if (mnt->mnt_parent == path2->mnt) @@ -2316,7 +2317,7 @@ int path_is_under(struct path *path1, struct path *path2) dentry = mnt->mnt_mountpoint; } res = is_subdir(dentry, path2->dentry); - spin_unlock(&vfsmount_lock); + br_read_unlock(vfsmount_lock); return res; } EXPORT_SYMBOL(path_is_under); diff --git a/fs/internal.h b/fs/internal.h index 6a5c13a8..a6910e9 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -9,6 +9,8 @@ * 2 of the License, or (at your option) any later version. */ +#include + struct super_block; struct linux_binprm; struct path; @@ -70,7 +72,8 @@ extern struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int); extern void __init mnt_init(void); -extern spinlock_t vfsmount_lock; +DECLARE_BRLOCK(vfsmount_lock); + /* * fs_struct.c diff --git a/fs/namei.c b/fs/namei.c index 11de7c3..24896e8 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -595,15 +595,16 @@ int follow_up(struct path *path) { struct vfsmount *parent; struct dentry *mountpoint; - spin_lock(&vfsmount_lock); + + br_read_lock(vfsmount_lock); parent = path->mnt->mnt_parent; if (parent == path->mnt) { - spin_unlock(&vfsmount_lock); + br_read_unlock(vfsmount_lock); return 0; } mntget(parent); mountpoint = dget(path->mnt->mnt_mountpoint); - spin_unlock(&vfsmount_lock); + br_read_unlock(vfsmount_lock); dput(path->dentry); path->dentry = mountpoint; mntput(path->mnt); diff --git a/fs/namespace.c b/fs/namespace.c index 2e10cb1..de402eb 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include #include @@ -38,12 +40,10 @@ #define HASH_SHIFT ilog2(PAGE_SIZE / sizeof(struct list_head)) #define HASH_SIZE (1UL << HASH_SHIFT) -/* spinlock for vfsmount related operations, inplace of dcache_lock */ -__cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); - static int event; static DEFINE_IDA(mnt_id_ida); static DEFINE_IDA(mnt_group_ida); +static DEFINE_SPINLOCK(mnt_id_lock); static int mnt_id_start = 0; static int mnt_group_start = 1; @@ -55,6 +55,16 @@ static struct rw_semaphore namespace_sem; struct kobject *fs_kobj; EXPORT_SYMBOL_GPL(fs_kobj); +/* + * vfsmount lock may be taken for read to prevent changes to the + * vfsmount hash, ie. during mountpoint lookups or walking back + * up the tree. + * + * It should be taken for write in all cases where the vfsmount + * tree or hash is modified or when a vfsmount structure is modified. + */ +DEFINE_BRLOCK(vfsmount_lock); + static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry) { unsigned long tmp = ((unsigned long)mnt / L1_CACHE_BYTES); @@ -65,18 +75,21 @@ static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry) #define MNT_WRITER_UNDERFLOW_LIMIT -(1<<16) -/* allocation is serialized by namespace_sem */ +/* + * allocation is serialized by namespace_sem, but we need the spinlock to + * serialize with freeing. + */ static int mnt_alloc_id(struct vfsmount *mnt) { int res; retry: ida_pre_get(&mnt_id_ida, GFP_KERNEL); - spin_lock(&vfsmount_lock); + spin_lock(&mnt_id_lock); res = ida_get_new_above(&mnt_id_ida, mnt_id_start, &mnt->mnt_id); if (!res) mnt_id_start = mnt->mnt_id + 1; - spin_unlock(&vfsmount_lock); + spin_unlock(&mnt_id_lock); if (res == -EAGAIN) goto retry; @@ -86,11 +99,11 @@ retry: static void mnt_free_id(struct vfsmount *mnt) { int id = mnt->mnt_id; - spin_lock(&vfsmount_lock); + spin_lock(&mnt_id_lock); ida_remove(&mnt_id_ida, id); if (mnt_id_start > id) mnt_id_start = id; - spin_unlock(&vfsmount_lock); + spin_unlock(&mnt_id_lock); } /* @@ -348,7 +361,7 @@ static int mnt_make_readonly(struct vfsmount *mnt) { int ret = 0; - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); mnt->mnt_flags |= MNT_WRITE_HOLD; /* * After storing MNT_WRITE_HOLD, we'll read the counters. This store @@ -382,15 +395,15 @@ static int mnt_make_readonly(struct vfsmount *mnt) */ smp_wmb(); mnt->mnt_flags &= ~MNT_WRITE_HOLD; - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); return ret; } static void __mnt_unmake_readonly(struct vfsmount *mnt) { - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); mnt->mnt_flags &= ~MNT_READONLY; - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); } void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb) @@ -414,6 +427,7 @@ void free_vfsmnt(struct vfsmount *mnt) /* * find the first or last mount at @dentry on vfsmount @mnt depending on * @dir. If @dir is set return the first mount else return the last mount. + * vfsmount_lock must be held for read or write. */ struct vfsmount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry, int dir) @@ -443,10 +457,11 @@ struct vfsmount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry, struct vfsmount *lookup_mnt(struct path *path) { struct vfsmount *child_mnt; - spin_lock(&vfsmount_lock); + + br_read_lock(vfsmount_lock); if ((child_mnt = __lookup_mnt(path->mnt, path->dentry, 1))) mntget(child_mnt); - spin_unlock(&vfsmount_lock); + br_read_unlock(vfsmount_lock); return child_mnt; } @@ -455,6 +470,9 @@ static inline int check_mnt(struct vfsmount *mnt) return mnt->mnt_ns == current->nsproxy->mnt_ns; } +/* + * vfsmount lock must be held for write + */ static void touch_mnt_namespace(struct mnt_namespace *ns) { if (ns) { @@ -463,6 +481,9 @@ static void touch_mnt_namespace(struct mnt_namespace *ns) } } +/* + * vfsmount lock must be held for write + */ static void __touch_mnt_namespace(struct mnt_namespace *ns) { if (ns && ns->event != event) { @@ -471,6 +492,9 @@ static void __touch_mnt_namespace(struct mnt_namespace *ns) } } +/* + * vfsmount lock must be held for write + */ static void detach_mnt(struct vfsmount *mnt, struct path *old_path) { old_path->dentry = mnt->mnt_mountpoint; @@ -482,6 +506,9 @@ static void detach_mnt(struct vfsmount *mnt, struct path *old_path) old_path->dentry->d_mounted--; } +/* + * vfsmount lock must be held for write + */ void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry, struct vfsmount *child_mnt) { @@ -490,6 +517,9 @@ void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry, dentry->d_mounted++; } +/* + * vfsmount lock must be held for write + */ static void attach_mnt(struct vfsmount *mnt, struct path *path) { mnt_set_mountpoint(path->mnt, path->dentry, mnt); @@ -499,7 +529,7 @@ static void attach_mnt(struct vfsmount *mnt, struct path *path) } /* - * the caller must hold vfsmount_lock + * vfsmount lock must be held for write */ static void commit_tree(struct vfsmount *mnt) { @@ -623,39 +653,43 @@ static inline void __mntput(struct vfsmount *mnt) void mntput_no_expire(struct vfsmount *mnt) { repeat: - if (atomic_dec_and_lock(&mnt->mnt_count, &vfsmount_lock)) { - if (likely(!mnt->mnt_pinned)) { - spin_unlock(&vfsmount_lock); - __mntput(mnt); - return; - } - atomic_add(mnt->mnt_pinned + 1, &mnt->mnt_count); - mnt->mnt_pinned = 0; - spin_unlock(&vfsmount_lock); - acct_auto_close_mnt(mnt); - goto repeat; + if (atomic_add_unless(&mnt->mnt_count, -1, 1)) + return; + br_write_lock(vfsmount_lock); + if (!atomic_dec_and_test(&mnt->mnt_count)) { + br_write_unlock(vfsmount_lock); + return; + } + if (likely(!mnt->mnt_pinned)) { + br_write_unlock(vfsmount_lock); + __mntput(mnt); + return; } + atomic_add(mnt->mnt_pinned + 1, &mnt->mnt_count); + mnt->mnt_pinned = 0; + br_write_unlock(vfsmount_lock); + acct_auto_close_mnt(mnt); + goto repeat; } - EXPORT_SYMBOL(mntput_no_expire); void mnt_pin(struct vfsmount *mnt) { - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); mnt->mnt_pinned++; - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); } EXPORT_SYMBOL(mnt_pin); void mnt_unpin(struct vfsmount *mnt) { - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); if (mnt->mnt_pinned) { atomic_inc(&mnt->mnt_count); mnt->mnt_pinned--; } - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); } EXPORT_SYMBOL(mnt_unpin); @@ -746,12 +780,12 @@ int mnt_had_events(struct proc_mounts *p) struct mnt_namespace *ns = p->ns; int res = 0; - spin_lock(&vfsmount_lock); + br_read_lock(vfsmount_lock); if (p->event != ns->event) { p->event = ns->event; res = 1; } - spin_unlock(&vfsmount_lock); + br_read_unlock(vfsmount_lock); return res; } @@ -952,12 +986,12 @@ int may_umount_tree(struct vfsmount *mnt) int minimum_refs = 0; struct vfsmount *p; - spin_lock(&vfsmount_lock); + br_read_lock(vfsmount_lock); for (p = mnt; p; p = next_mnt(p, mnt)) { actual_refs += atomic_read(&p->mnt_count); minimum_refs += 2; } - spin_unlock(&vfsmount_lock); + br_read_unlock(vfsmount_lock); if (actual_refs > minimum_refs) return 0; @@ -984,10 +1018,10 @@ int may_umount(struct vfsmount *mnt) { int ret = 1; down_read(&namespace_sem); - spin_lock(&vfsmount_lock); + br_read_lock(vfsmount_lock); if (propagate_mount_busy(mnt, 2)) ret = 0; - spin_unlock(&vfsmount_lock); + br_read_unlock(vfsmount_lock); up_read(&namespace_sem); return ret; } @@ -1003,13 +1037,14 @@ void release_mounts(struct list_head *head) if (mnt->mnt_parent != mnt) { struct dentry *dentry; struct vfsmount *m; - spin_lock(&vfsmount_lock); + + br_write_lock(vfsmount_lock); dentry = mnt->mnt_mountpoint; m = mnt->mnt_parent; mnt->mnt_mountpoint = mnt->mnt_root; mnt->mnt_parent = mnt; m->mnt_ghosts--; - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); dput(dentry); mntput(m); } @@ -1017,6 +1052,10 @@ void release_mounts(struct list_head *head) } } +/* + * vfsmount lock must be held for write + * namespace_sem must be held for write + */ void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) { struct vfsmount *p; @@ -1107,7 +1146,7 @@ static int do_umount(struct vfsmount *mnt, int flags) } down_write(&namespace_sem); - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); event++; if (!(flags & MNT_DETACH)) @@ -1119,7 +1158,7 @@ static int do_umount(struct vfsmount *mnt, int flags) umount_tree(mnt, 1, &umount_list); retval = 0; } - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); up_write(&namespace_sem); release_mounts(&umount_list); return retval; @@ -1231,19 +1270,19 @@ struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry, q = clone_mnt(p, p->mnt_root, flag); if (!q) goto Enomem; - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); list_add_tail(&q->mnt_list, &res->mnt_list); attach_mnt(q, &path); - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); } } return res; Enomem: if (res) { LIST_HEAD(umount_list); - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); umount_tree(res, 0, &umount_list); - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); release_mounts(&umount_list); } return NULL; @@ -1262,9 +1301,9 @@ void drop_collected_mounts(struct vfsmount *mnt) { LIST_HEAD(umount_list); down_write(&namespace_sem); - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); umount_tree(mnt, 0, &umount_list); - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); up_write(&namespace_sem); release_mounts(&umount_list); } @@ -1392,7 +1431,7 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt, if (err) goto out_cleanup_ids; - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); if (IS_MNT_SHARED(dest_mnt)) { for (p = source_mnt; p; p = next_mnt(p, source_mnt)) @@ -1411,7 +1450,8 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt, list_del_init(&child->mnt_hash); commit_tree(child); } - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); + return 0; out_cleanup_ids: @@ -1466,10 +1506,10 @@ static int do_change_type(struct path *path, int flag) goto out_unlock; } - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); for (m = mnt; m; m = (recurse ? next_mnt(m, mnt) : NULL)) change_mnt_propagation(m, type); - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); out_unlock: up_write(&namespace_sem); @@ -1513,9 +1553,10 @@ static int do_loopback(struct path *path, char *old_name, err = graft_tree(mnt, path); if (err) { LIST_HEAD(umount_list); - spin_lock(&vfsmount_lock); + + br_write_lock(vfsmount_lock); umount_tree(mnt, 0, &umount_list); - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); release_mounts(&umount_list); } @@ -1568,16 +1609,16 @@ static int do_remount(struct path *path, int flags, int mnt_flags, else err = do_remount_sb(sb, flags, data, 0); if (!err) { - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); mnt_flags |= path->mnt->mnt_flags & MNT_PROPAGATION_MASK; path->mnt->mnt_flags = mnt_flags; - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); } up_write(&sb->s_umount); if (!err) { - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); touch_mnt_namespace(path->mnt->mnt_ns); - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); } return err; } @@ -1754,7 +1795,7 @@ void mark_mounts_for_expiry(struct list_head *mounts) return; down_write(&namespace_sem); - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); /* extract from the expiration list every vfsmount that matches the * following criteria: @@ -1773,7 +1814,7 @@ void mark_mounts_for_expiry(struct list_head *mounts) touch_mnt_namespace(mnt->mnt_ns); umount_tree(mnt, 1, &umounts); } - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); up_write(&namespace_sem); release_mounts(&umounts); @@ -1830,6 +1871,8 @@ resume: /* * process a list of expirable mountpoints with the intent of discarding any * submounts of a specific parent mountpoint + * + * vfsmount_lock must be held for write */ static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts) { @@ -2048,9 +2091,9 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, kfree(new_ns); return ERR_PTR(-ENOMEM); } - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); list_add_tail(&new_ns->list, &new_ns->root->mnt_list); - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); /* * Second pass: switch the tsk->fs->* elements and mark new vfsmounts @@ -2244,7 +2287,7 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, goto out2; /* not attached */ /* make sure we can reach put_old from new_root */ tmp = old.mnt; - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); if (tmp != new.mnt) { for (;;) { if (tmp->mnt_parent == tmp) @@ -2264,7 +2307,7 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, /* mount new_root on / */ attach_mnt(new.mnt, &root_parent); touch_mnt_namespace(current->nsproxy->mnt_ns); - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); chroot_fs_refs(&root, &new); error = 0; path_put(&root_parent); @@ -2279,7 +2322,7 @@ out1: out0: return error; out3: - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); goto out2; } @@ -2326,6 +2369,8 @@ void __init mnt_init(void) for (u = 0; u < HASH_SIZE; u++) INIT_LIST_HEAD(&mount_hashtable[u]); + br_lock_init(vfsmount_lock); + err = sysfs_init(); if (err) printk(KERN_WARNING "%s: sysfs_init error: %d\n", @@ -2344,9 +2389,9 @@ void put_mnt_ns(struct mnt_namespace *ns) if (!atomic_dec_and_test(&ns->count)) return; down_write(&namespace_sem); - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); umount_tree(ns->root, 0, &umount_list); - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); up_write(&namespace_sem); release_mounts(&umount_list); kfree(ns); diff --git a/fs/pnode.c b/fs/pnode.c index 5cc564a..8066b8d 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -126,6 +126,9 @@ static int do_make_slave(struct vfsmount *mnt) return 0; } +/* + * vfsmount lock must be held for write + */ void change_mnt_propagation(struct vfsmount *mnt, int type) { if (type == MS_SHARED) { @@ -270,12 +273,12 @@ int propagate_mnt(struct vfsmount *dest_mnt, struct dentry *dest_dentry, prev_src_mnt = child; } out: - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); while (!list_empty(&tmp_list)) { child = list_first_entry(&tmp_list, struct vfsmount, mnt_hash); umount_tree(child, 0, &umount_list); } - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); release_mounts(&umount_list); return ret; } @@ -296,6 +299,8 @@ static inline int do_refcount_check(struct vfsmount *mnt, int count) * other mounts its parent propagates to. * Check if any of these mounts that **do not have submounts** * have more references than 'refcnt'. If so return busy. + * + * vfsmount lock must be held for read or write */ int propagate_mount_busy(struct vfsmount *mnt, int refcnt) { @@ -353,6 +358,8 @@ static void __propagate_umount(struct vfsmount *mnt) * collect all mounts that receive propagation from the mount in @list, * and return these additional mounts in the same list. * @list: the list of mounts to be unmounted. + * + * vfsmount lock must be held for write */ int propagate_umount(struct list_head *list) { -- cgit v0.10.2 From 56385a12d9bb9e173751f74b6c430742018cafc0 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 18 Aug 2010 14:08:17 +0200 Subject: ALSA: emu10k1 - delay the PCM interrupts (add pcm_irq_delay parameter) With some hardware combinations, the PCM interrupts are acknowledged before the period boundary from the emu10k1 chip. The midlevel PCM code gets confused and the playback stream is interrupted. It seems that the interrupt processing shift by 2 samples is enough to fix this issue. This default value does not harm other, non-affected hardware. More information: Kernel bugzilla bug#16300 [A copmile warning fixed by tiwai] Signed-off-by: Jaroslav Kysela Cc: Signed-off-by: Takashi Iwai diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 6a664c3..7dc97d1 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1707,6 +1707,7 @@ struct snd_emu10k1 { unsigned int card_type; /* EMU10K1_CARD_* */ unsigned int ecard_ctrl; /* ecard control bits */ unsigned long dma_mask; /* PCI DMA mask */ + unsigned int delay_pcm_irq; /* in samples */ int max_cache_pages; /* max memory size / PAGE_SIZE */ struct snd_dma_buffer silent_page; /* silent page */ struct snd_dma_buffer ptb_pages; /* page table pages */ diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index a3b2a64..134fc6c 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -978,6 +978,10 @@ static int snd_pcm_do_pause(struct snd_pcm_substream *substream, int push) { if (substream->runtime->trigger_master != substream) return 0; + /* some drivers might use hw_ptr to recover from the pause - + update the hw_ptr now */ + if (push) + snd_pcm_update_hw_ptr(substream); /* The jiffies check in snd_pcm_update_hw_ptr*() is done by * a delta betwen the current jiffies, this gives a large enough * delta, effectively to skip the check once. diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 4203782..aff8387 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -52,6 +52,7 @@ static int max_synth_voices[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 64}; static int max_buffer_size[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 128}; static int enable_ir[SNDRV_CARDS]; static uint subsystem[SNDRV_CARDS]; /* Force card subsystem model */ +static uint delay_pcm_irq[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for the EMU10K1 soundcard."); @@ -73,6 +74,8 @@ module_param_array(enable_ir, bool, NULL, 0444); MODULE_PARM_DESC(enable_ir, "Enable IR."); module_param_array(subsystem, uint, NULL, 0444); MODULE_PARM_DESC(subsystem, "Force card subsystem model."); +module_param_array(delay_pcm_irq, uint, NULL, 0444); +MODULE_PARM_DESC(delay_pcm_irq, "Delay PCM interrupt by specified number of samples (default 0)."); /* * Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value Model:SB0400 */ @@ -127,6 +130,7 @@ static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci, &emu)) < 0) goto error; card->private_data = emu; + emu->delay_pcm_irq = delay_pcm_irq[dev] & 0x1f; if ((err = snd_emu10k1_pcm(emu, 0, NULL)) < 0) goto error; if ((err = snd_emu10k1_pcm_mic(emu, 1, NULL)) < 0) diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 55b83ef..622bace 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -332,7 +332,7 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, evoice->epcm->ccca_start_addr = start_addr + ccis; if (extra) { start_addr += ccis; - end_addr += ccis; + end_addr += ccis + emu->delay_pcm_irq; } if (stereo && !extra) { snd_emu10k1_ptr_write(emu, CPF, voice, CPF_STEREO_MASK); @@ -360,7 +360,9 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, /* Assumption that PT is already 0 so no harm overwriting */ snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]); snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24)); - snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24)); + snd_emu10k1_ptr_write(emu, PSST, voice, + (start_addr + (extra ? emu->delay_pcm_irq : 0)) | + (send_amount[2] << 24)); if (emu->card_capabilities->emu_model) pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ else @@ -732,6 +734,23 @@ static void snd_emu10k1_playback_stop_voice(struct snd_emu10k1 *emu, struct snd_ snd_emu10k1_ptr_write(emu, IP, voice, 0); } +static inline void snd_emu10k1_playback_mangle_extra(struct snd_emu10k1 *emu, + struct snd_emu10k1_pcm *epcm, + struct snd_pcm_substream *substream, + struct snd_pcm_runtime *runtime) +{ + unsigned int ptr, period_pos; + + /* try to sychronize the current position for the interrupt + source voice */ + period_pos = runtime->status->hw_ptr - runtime->hw_ptr_interrupt; + period_pos %= runtime->period_size; + ptr = snd_emu10k1_ptr_read(emu, CCCA, epcm->extra->number); + ptr &= ~0x00ffffff; + ptr |= epcm->ccca_start_addr + period_pos; + snd_emu10k1_ptr_write(emu, CCCA, epcm->extra->number, ptr); +} + static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream, int cmd) { @@ -753,6 +772,8 @@ static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream, /* follow thru */ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME: + if (cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE) + snd_emu10k1_playback_mangle_extra(emu, epcm, substream, runtime); mix = &emu->pcm_mixer[substream->number]; snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 1, 0, mix); snd_emu10k1_playback_prepare_voice(emu, epcm->voices[1], 0, 0, mix); @@ -869,8 +890,9 @@ static snd_pcm_uframes_t snd_emu10k1_playback_pointer(struct snd_pcm_substream * #endif /* printk(KERN_DEBUG - "ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n", - ptr, runtime->buffer_size, runtime->period_size); + "ptr = 0x%lx, buffer_size = 0x%lx, period_size = 0x%lx\n", + (long)ptr, (long)runtime->buffer_size, + (long)runtime->period_size); */ return ptr; } diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index ffb1ddb..957a311 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -310,8 +310,10 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst if (snd_BUG_ON(!hdr)) return NULL; + idx = runtime->period_size >= runtime->buffer_size ? + (emu->delay_pcm_irq * 2) : 0; mutex_lock(&hdr->block_mutex); - blk = search_empty(emu, runtime->dma_bytes); + blk = search_empty(emu, runtime->dma_bytes + idx); if (blk == NULL) { mutex_unlock(&hdr->block_mutex); return NULL; -- cgit v0.10.2 From 0a377cff9428af2da2b293d11e07bc4dbf064ee5 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 18 Aug 2010 09:25:42 -0400 Subject: NFS: Fix an Oops in the NFSv4 atomic open code Adam Lackorzynski reports: with 2.6.35.2 I'm getting this reproducible Oops: [ 110.825396] BUG: unable to handle kernel NULL pointer dereference at (null) [ 110.828638] IP: [] encode_attrs+0x1a/0x2a4 [ 110.828638] PGD be89f067 PUD bf18f067 PMD 0 [ 110.828638] Oops: 0000 [#1] SMP [ 110.828638] last sysfs file: /sys/class/net/lo/operstate [ 110.828638] CPU 2 [ 110.828638] Modules linked in: rtc_cmos rtc_core rtc_lib amd64_edac_mod i2c_amd756 edac_core i2c_core dm_mirror dm_region_hash dm_log dm_snapshot sg sr_mod usb_storage ohci_hcd mptspi tg3 mptscsih mptbase usbcore nls_base [last unloaded: scsi_wait_scan] [ 110.828638] [ 110.828638] Pid: 11264, comm: setchecksum Not tainted 2.6.35.2 #1 [ 110.828638] RIP: 0010:[] [] encode_attrs+0x1a/0x2a4 [ 110.828638] RSP: 0000:ffff88003bf5b878 EFLAGS: 00010296 [ 110.828638] RAX: ffff8800bddb48a8 RBX: ffff88003bf5bb18 RCX: 0000000000000000 [ 110.828638] RDX: ffff8800be258800 RSI: 0000000000000000 RDI: ffff88003bf5b9f8 [ 110.828638] RBP: 0000000000000000 R08: ffff8800bddb48a8 R09: 0000000000000004 [ 110.828638] R10: 0000000000000003 R11: ffff8800be779000 R12: ffff8800be258800 [ 110.828638] R13: ffff88003bf5b9f8 R14: ffff88003bf5bb20 R15: ffff8800be258800 [ 110.828638] FS: 0000000000000000(0000) GS:ffff880041e00000(0063) knlGS:00000000556bd6b0 [ 110.828638] CS: 0010 DS: 002b ES: 002b CR0: 000000008005003b [ 110.828638] CR2: 0000000000000000 CR3: 00000000be8ef000 CR4: 00000000000006e0 [ 110.828638] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 110.828638] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 [ 110.828638] Process setchecksum (pid: 11264, threadinfo ffff88003bf5a000, task ffff88003f232210) [ 110.828638] Stack: [ 110.828638] 0000000000000000 ffff8800bfbcf920 0000000000000000 0000000000000ffe [ 110.828638] <0> 0000000000000000 0000000000000000 0000000000000000 0000000000000000 [ 110.828638] <0> 0000000000000000 0000000000000000 0000000000000000 0000000000000000 [ 110.828638] Call Trace: [ 110.828638] [] ? nfs4_xdr_enc_setattr+0x90/0xb4 [ 110.828638] [] ? call_transmit+0x1c3/0x24a [ 110.828638] [] ? __rpc_execute+0x78/0x22a [ 110.828638] [] ? rpc_run_task+0x21/0x2b [ 110.828638] [] ? rpc_call_sync+0x3d/0x5d [ 110.828638] [] ? _nfs4_do_setattr+0x11b/0x147 [ 110.828638] [] ? nfs_init_locked+0x0/0x32 [ 110.828638] [] ? ifind+0x4e/0x90 [ 110.828638] [] ? nfs4_do_setattr+0x4b/0x6e [ 110.828638] [] ? nfs4_do_open+0x291/0x3a6 [ 110.828638] [] ? nfs4_open_revalidate+0x63/0x14a [ 110.828638] [] ? nfs_open_revalidate+0xd7/0x161 [ 110.828638] [] ? do_lookup+0x1a4/0x201 [ 110.828638] [] ? link_path_walk+0x6a/0x9d5 [ 110.828638] [] ? do_last+0x17b/0x58e [ 110.828638] [] ? do_filp_open+0x1bd/0x56e [ 110.828638] [] ? _atomic_dec_and_lock+0x30/0x48 [ 110.828638] [] ? dput+0x37/0x152 [ 110.828638] [] ? alloc_fd+0x69/0x10a [ 110.828638] [] ? do_sys_open+0x56/0x100 [ 110.828638] [] ? ia32_sysret+0x0/0x5 [ 110.828638] Code: 83 f1 01 e8 f5 ca ff ff 48 83 c4 50 5b 5d 41 5c c3 41 57 41 56 41 55 49 89 fd 41 54 49 89 d4 55 48 89 f5 53 48 81 ec 18 01 00 00 <8b> 06 89 c2 83 e2 08 83 fa 01 19 db 83 e3 f8 83 c3 18 a8 01 8d [ 110.828638] RIP [] encode_attrs+0x1a/0x2a4 [ 110.828638] RSP [ 110.828638] CR2: 0000000000000000 [ 112.840396] ---[ end trace 95282e83fd77358f ]--- We need to ensure that the O_EXCL flag is turned off if the user doesn't set O_CREAT. Cc: stable@kernel.org Signed-off-by: Trond Myklebust diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index bd91b27..e257172 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1110,7 +1110,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) goto no_open_dput; /* We can't create new files, or truncate existing ones here */ - openflags &= ~(O_CREAT|O_TRUNC); + openflags &= ~(O_CREAT|O_EXCL|O_TRUNC); /* * Note: we're not holding inode->i_mutex and so may be racing with diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 6b44bbf..089da5b 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2036,7 +2036,8 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) struct rpc_cred *cred; struct nfs4_state *state; struct dentry *res; - fmode_t fmode = nd->intent.open.flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC); + int open_flags = nd->intent.open.flags; + fmode_t fmode = open_flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC); if (nd->flags & LOOKUP_CREATE) { attr.ia_mode = nd->intent.open.create_mode; @@ -2044,8 +2045,9 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) if (!IS_POSIXACL(dir)) attr.ia_mode &= ~current_umask(); } else { + open_flags &= ~O_EXCL; attr.ia_valid = 0; - BUG_ON(nd->intent.open.flags & O_CREAT); + BUG_ON(open_flags & O_CREAT); } cred = rpc_lookup_cred(); @@ -2054,7 +2056,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) parent = dentry->d_parent; /* Protect against concurrent sillydeletes */ nfs_block_sillyrename(parent); - state = nfs4_do_open(dir, &path, fmode, nd->intent.open.flags, &attr, cred); + state = nfs4_do_open(dir, &path, fmode, open_flags, &attr, cred); put_rpccred(cred); if (IS_ERR(state)) { if (PTR_ERR(state) == -ENOENT) { -- cgit v0.10.2 From 1cb0c924fa2d616e5e3b5bc62d97191aac9ff442 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Wed, 18 Aug 2010 21:11:11 +0900 Subject: nilfs2: wait for discard to finish nilfs_discard_segment() doesn't wait for completion of discard requests. This specifies BLKDEV_IFL_WAIT flag when calling blkdev_issue_discard() in order to fix the sync failure. Reported-by: Christoph Hellwig Signed-off-by: Ryusuke Konishi Cc: Christoph Hellwig diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 6af1c00..4317f17 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c @@ -775,6 +775,7 @@ int nilfs_discard_segments(struct the_nilfs *nilfs, __u64 *segnump, start * sects_per_block, nblocks * sects_per_block, GFP_NOFS, + BLKDEV_IFL_WAIT | BLKDEV_IFL_BARRIER); if (ret < 0) return ret; @@ -785,7 +786,8 @@ int nilfs_discard_segments(struct the_nilfs *nilfs, __u64 *segnump, ret = blkdev_issue_discard(nilfs->ns_bdev, start * sects_per_block, nblocks * sects_per_block, - GFP_NOFS, BLKDEV_IFL_BARRIER); + GFP_NOFS, + BLKDEV_IFL_WAIT | BLKDEV_IFL_BARRIER); return ret; } -- cgit v0.10.2 From 07a7795ca2e6e66d00b184efb46bd0e23d90d3fe Mon Sep 17 00:00:00 2001 From: Hans Rosenfeld Date: Wed, 18 Aug 2010 16:19:50 +0200 Subject: x86, cpu: Fix regression in AMD errata checking code A bug in the family-model-stepping matching code caused the presence of errata to go undetected when OSVW was not used. This causes hangs on some K8 systems because the E400 workaround is not enabled. Signed-off-by: Hans Rosenfeld LKML-Reference: <1282141190-930137-1-git-send-email-hans.rosenfeld@amd.com> Signed-off-by: H. Peter Anvin diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 60a57b1..ba5f62f 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -669,7 +669,7 @@ bool cpu_has_amd_erratum(const int *erratum) } /* OSVW unavailable or ID unknown, match family-model-stepping range */ - ms = (cpu->x86_model << 8) | cpu->x86_mask; + ms = (cpu->x86_model << 4) | cpu->x86_mask; while ((range = *erratum++)) if ((cpu->x86 == AMD_MODEL_RANGE_FAMILY(range)) && (ms >= AMD_MODEL_RANGE_START(range)) && -- cgit v0.10.2 From fd89a137924e0710078c3ae855e7cec1c43cb845 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 16 Aug 2010 14:38:33 +0200 Subject: x86-32: Separate 1:1 pagetables from swapper_pg_dir This patch fixes machine crashes which occur when heavily exercising the CPU hotplug codepaths on a 32-bit kernel. These crashes are caused by AMD Erratum 383 and result in a fatal machine check exception. Here's the scenario: 1. On 32-bit, the swapper_pg_dir page table is used as the initial page table for booting a secondary CPU. 2. To make this work, swapper_pg_dir needs a direct mapping of physical memory in it (the low mappings). By adding those low, large page (2M) mappings (PAE kernel), we create the necessary conditions for Erratum 383 to occur. 3. Other CPUs which do not participate in the off- and onlining game may use swapper_pg_dir while the low mappings are present (when leave_mm is called). For all steps below, the CPU referred to is a CPU that is using swapper_pg_dir, and not the CPU which is being onlined. 4. The presence of the low mappings in swapper_pg_dir can result in TLB entries for addresses below __PAGE_OFFSET to be established speculatively. These TLB entries are marked global and large. 5. When the CPU with such TLB entry switches to another page table, this TLB entry remains because it is global. 6. The process then generates an access to an address covered by the above TLB entry but there is a permission mismatch - the TLB entry covers a large global page not accessible to userspace. 7. Due to this permission mismatch a new 4kb, user TLB entry gets established. Further, Erratum 383 provides for a small window of time where both TLB entries are present. This results in an uncorrectable machine check exception signalling a TLB multimatch which panics the machine. There are two ways to fix this issue: 1. Always do a global TLB flush when a new cr3 is loaded and the old page table was swapper_pg_dir. I consider this a hack hard to understand and with performance implications 2. Do not use swapper_pg_dir to boot secondary CPUs like 64-bit does. This patch implements solution 2. It introduces a trampoline_pg_dir which has the same layout as swapper_pg_dir with low_mappings. This page table is used as the initial page table of the booting CPU. Later in the bringup process, it switches to swapper_pg_dir and does a global TLB flush. This fixes the crashes in our test cases. -v2: switch to swapper_pg_dir right after entering start_secondary() so that we are able to access percpu data which might not be mapped in the trampoline page table. Signed-off-by: Joerg Roedel LKML-Reference: <20100816123833.GB28147@aftab> Signed-off-by: Borislav Petkov Signed-off-by: H. Peter Anvin diff --git a/arch/x86/include/asm/pgtable_32.h b/arch/x86/include/asm/pgtable_32.h index 2984a25..f686f49 100644 --- a/arch/x86/include/asm/pgtable_32.h +++ b/arch/x86/include/asm/pgtable_32.h @@ -26,6 +26,7 @@ struct mm_struct; struct vm_area_struct; extern pgd_t swapper_pg_dir[1024]; +extern pgd_t trampoline_pg_dir[1024]; static inline void pgtable_cache_init(void) { } static inline void check_pgt_cache(void) { } diff --git a/arch/x86/include/asm/trampoline.h b/arch/x86/include/asm/trampoline.h index cb507bb..8f78fdf 100644 --- a/arch/x86/include/asm/trampoline.h +++ b/arch/x86/include/asm/trampoline.h @@ -13,14 +13,17 @@ extern unsigned char *trampoline_base; extern unsigned long init_rsp; extern unsigned long initial_code; +extern unsigned long initial_page_table; extern unsigned long initial_gs; #define TRAMPOLINE_SIZE roundup(trampoline_end - trampoline_data, PAGE_SIZE) extern unsigned long setup_trampoline(void); +extern void __init setup_trampoline_page_table(void); extern void __init reserve_trampoline_memory(void); #else static inline void reserve_trampoline_memory(void) {}; +extern void __init setup_trampoline_page_table(void) {}; #endif /* CONFIG_X86_TRAMPOLINE */ #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S index ff4c453..fa8c1b8 100644 --- a/arch/x86/kernel/head_32.S +++ b/arch/x86/kernel/head_32.S @@ -334,7 +334,7 @@ ENTRY(startup_32_smp) /* * Enable paging */ - movl $pa(swapper_pg_dir),%eax + movl pa(initial_page_table), %eax movl %eax,%cr3 /* set the page table pointer.. */ movl %cr0,%eax orl $X86_CR0_PG,%eax @@ -614,6 +614,8 @@ ignore_int: .align 4 ENTRY(initial_code) .long i386_start_kernel +ENTRY(initial_page_table) + .long pa(swapper_pg_dir) /* * BSS section @@ -629,6 +631,10 @@ ENTRY(swapper_pg_dir) #endif swapper_pg_fixmap: .fill 1024,4,0 +#ifdef CONFIG_X86_TRAMPOLINE +ENTRY(trampoline_pg_dir) + .fill 1024,4,0 +#endif ENTRY(empty_zero_page) .fill 4096,1,0 diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index b008e78..c3a4fbb 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -1014,6 +1014,8 @@ void __init setup_arch(char **cmdline_p) paging_init(); x86_init.paging.pagetable_setup_done(swapper_pg_dir); + setup_trampoline_page_table(); + tboot_probe(); #ifdef CONFIG_X86_64 diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index a5e928b..abf4a86 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -73,7 +73,6 @@ #ifdef CONFIG_X86_32 u8 apicid_2_node[MAX_APICID]; -static int low_mappings; #endif /* State of each CPU */ @@ -281,6 +280,18 @@ notrace static void __cpuinit start_secondary(void *unused) * fragile that we want to limit the things done here to the * most necessary things. */ + +#ifdef CONFIG_X86_32 + /* + * Switch away from the trampoline page-table + * + * Do this before cpu_init() because it needs to access per-cpu + * data which may not be mapped in the trampoline page-table. + */ + load_cr3(swapper_pg_dir); + __flush_tlb_all(); +#endif + vmi_bringup(); cpu_init(); preempt_disable(); @@ -299,12 +310,6 @@ notrace static void __cpuinit start_secondary(void *unused) legacy_pic->chip->unmask(0); } -#ifdef CONFIG_X86_32 - while (low_mappings) - cpu_relax(); - __flush_tlb_all(); -#endif - /* This must be done before setting cpu_online_mask */ set_cpu_sibling_map(raw_smp_processor_id()); wmb(); @@ -750,6 +755,7 @@ do_rest: #ifdef CONFIG_X86_32 /* Stack for startup_32 can be just as for start_secondary onwards */ irq_ctx_init(cpu); + initial_page_table = __pa(&trampoline_pg_dir); #else clear_tsk_thread_flag(c_idle.idle, TIF_FORK); initial_gs = per_cpu_offset(cpu); @@ -897,20 +903,8 @@ int __cpuinit native_cpu_up(unsigned int cpu) per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; -#ifdef CONFIG_X86_32 - /* init low mem mapping */ - clone_pgd_range(swapper_pg_dir, swapper_pg_dir + KERNEL_PGD_BOUNDARY, - min_t(unsigned long, KERNEL_PGD_PTRS, KERNEL_PGD_BOUNDARY)); - flush_tlb_all(); - low_mappings = 1; - err = do_boot_cpu(apicid, cpu); - zap_low_mappings(false); - low_mappings = 0; -#else - err = do_boot_cpu(apicid, cpu); -#endif if (err) { pr_debug("do_boot_cpu failed %d\n", err); return -EIO; diff --git a/arch/x86/kernel/trampoline.c b/arch/x86/kernel/trampoline.c index c652ef6..a874495 100644 --- a/arch/x86/kernel/trampoline.c +++ b/arch/x86/kernel/trampoline.c @@ -1,6 +1,7 @@ #include #include +#include #include #if defined(CONFIG_X86_64) && defined(CONFIG_ACPI_SLEEP) @@ -37,3 +38,20 @@ unsigned long __trampinit setup_trampoline(void) memcpy(trampoline_base, trampoline_data, TRAMPOLINE_SIZE); return virt_to_phys(trampoline_base); } + +void __init setup_trampoline_page_table(void) +{ +#ifdef CONFIG_X86_32 + /* Copy kernel address range */ + clone_pgd_range(trampoline_pg_dir + KERNEL_PGD_BOUNDARY, + swapper_pg_dir + KERNEL_PGD_BOUNDARY, + min_t(unsigned long, KERNEL_PGD_PTRS, + KERNEL_PGD_BOUNDARY)); + + /* Initialize low mappings */ + clone_pgd_range(trampoline_pg_dir, + swapper_pg_dir + KERNEL_PGD_BOUNDARY, + min_t(unsigned long, KERNEL_PGD_PTRS, + KERNEL_PGD_BOUNDARY)); +#endif +} -- cgit v0.10.2 From ecafda60e88031bcc4271c446f984ee883d69ea8 Mon Sep 17 00:00:00 2001 From: Kusanagi Kouichi Date: Wed, 18 Aug 2010 13:32:37 -0300 Subject: perf tools: Fix build error on read only source. Parts of the build process were generating files outside the specified O= directory, causing the build to fail on systems where the sources are in a read only file system. Fix it by using $(OUTPUT) on these locations. Also check that $(OUTPUT) actually exists, just like the top level kernel Makefile does. Otherwise the failure message emitted is completely misleading. Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <20100817140841.0859362C03A@msa106.auone-net.jp> Signed-off-by: Kusanagi Kouichi Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Makefile b/tools/perf/Makefile index dcb9700..4f1fa77 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -5,6 +5,12 @@ endif # The default target of this Makefile is... all:: +ifneq ($(OUTPUT),) +# check that the output directory actually exists +OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd) +$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) +endif + # Define V=1 to have a more verbose compile. # Define V=2 to have an even more verbose compile. # @@ -931,15 +937,15 @@ $(OUTPUT)common-cmds.h: $(wildcard Documentation/perf-*.txt) $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh - $(QUIET_GEN)$(RM) $@ $@+ && \ + $(QUIET_GEN)$(RM) $(OUTPUT)$@ $(OUTPUT)$@+ && \ sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \ -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \ -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \ -e 's/@@NO_CURL@@/$(NO_CURL)/g' \ - $@.sh >$@+ && \ - chmod +x $@+ && \ - mv $@+ $(OUTPUT)$@ + $@.sh > $(OUTPUT)$@+ && \ + chmod +x $(OUTPUT)$@+ && \ + mv $(OUTPUT)$@+ $(OUTPUT)$@ configure: configure.ac $(QUIET_GEN)$(RM) $@ $<+ && \ diff --git a/tools/perf/feature-tests.mak b/tools/perf/feature-tests.mak index ddb68e6..7a7b608 100644 --- a/tools/perf/feature-tests.mak +++ b/tools/perf/feature-tests.mak @@ -113,7 +113,7 @@ endef # try-cc # Usage: option = $(call try-cc, source-to-build, cc-options) try-cc = $(shell sh -c \ - 'TMP="$(TMPOUT).$$$$"; \ + 'TMP="$(OUTPUT)$(TMPOUT).$$$$"; \ echo "$(1)" | \ $(CC) -x c - $(2) -o "$$TMP" > /dev/null 2>&1 && echo y; \ rm -f "$$TMP"') -- cgit v0.10.2 From 81ca03a0e2ea0207b2df80e0edcf4c775c07a505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 18 Aug 2010 09:25:38 -0700 Subject: mmc: build fix: mmc_pm_notify is only available with CONFIG_PM=y MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a build breakage introduced by commit 4c2ef25fe0b8 ("mmc: fix all hangs related to mmc/sd card insert/removal during suspend/resume") Cc: David Brownell Cc: Alan Stern Cc: linux-mmc@vger.kernel.org Cc: Andrew Morton Signed-off-by: Uwe Kleine-König Acked-by: Kukjin Kim Acked-by: Maxim Levitsky Acked-by: Randy Dunlap Signed-off-by: Linus Torvalds diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 0efe631..d80cfdc 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -86,7 +86,9 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) init_waitqueue_head(&host->wq); INIT_DELAYED_WORK(&host->detect, mmc_rescan); INIT_DELAYED_WORK_DEFERRABLE(&host->disable, mmc_host_deeper_disable); +#ifdef CONFIG_PM host->pm_notify.notifier_call = mmc_pm_notify; +#endif /* * By default, hosts do not support SGIO or large requests. -- cgit v0.10.2 From 145e5aa269d54e4ea53fdb5e597007bd287fbe49 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Wed, 18 Aug 2010 10:17:44 -0700 Subject: =?UTF-8?q?[IA64]=20Fix=20build=20error:=20conflicting=20types=20f?= =?UTF-8?q?or=20=E2=80=98sys=5Fexecve=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit arch/ia64/kernel/process.c:636: error: conflicting types for ‘sys_execve’ commit d7627467b7a8dd6944885290a03a07ceb28c10eb Make do_execve() take a const filename pointer Missed the declaration of sys_execve in the ia64 asm/unistd.h (perhaps because there is no reason for it to be there ... it might be a left over from the COMPAT code?). Just delete the conflicting version. Signed-off-by: Tony Luck diff --git a/arch/ia64/include/asm/unistd.h b/arch/ia64/include/asm/unistd.h index 87f1bd1..954d398 100644 --- a/arch/ia64/include/asm/unistd.h +++ b/arch/ia64/include/asm/unistd.h @@ -356,8 +356,6 @@ asmlinkage unsigned long sys_mmap2( int fd, long pgoff); struct pt_regs; struct sigaction; -long sys_execve(const char __user *filename, char __user * __user *argv, - char __user * __user *envp, struct pt_regs *regs); asmlinkage long sys_ia64_pipe(void); asmlinkage long sys_rt_sigaction(int sig, const struct sigaction __user *act, -- cgit v0.10.2 From d15ca3203754359cfe5d18910722d3089b204cc4 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 18 Aug 2010 18:55:33 +0100 Subject: Fix the declaration of sys_execve() in asm-generic/syscalls.h Fix the declaration of sys_execve() in asm-generic/syscalls.h to have various consts applied to its pointers. Signed-off-by: David Howells Signed-off-by: Linus Torvalds diff --git a/include/asm-generic/syscalls.h b/include/asm-generic/syscalls.h index df84e3b..d89dec8 100644 --- a/include/asm-generic/syscalls.h +++ b/include/asm-generic/syscalls.h @@ -23,8 +23,10 @@ asmlinkage long sys_vfork(struct pt_regs *regs); #endif #ifndef sys_execve -asmlinkage long sys_execve(char __user *filename, char __user * __user *argv, - char __user * __user *envp, struct pt_regs *regs); +asmlinkage long sys_execve(const char __user *filename, + const char __user *const __user *argv, + const char __user *const __user *envp, + struct pt_regs *regs); #endif #ifndef sys_mmap2 -- cgit v0.10.2 From 8848a91068c018bc91f597038a0f41462a0f88a4 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 18 Aug 2010 11:42:23 -0700 Subject: x86-32: Fix dummy trampoline-related inline stubs Fix dummy inline stubs for trampoline-related functions when no trampolines exist (until we get rid of the no-trampoline case entirely.) Signed-off-by: H. Peter Anvin Cc: Joerg Roedel Cc: Borislav Petkov LKML-Reference: <4C6C294D.3030404@zytor.com> diff --git a/arch/x86/include/asm/trampoline.h b/arch/x86/include/asm/trampoline.h index 8f78fdf..4dde797 100644 --- a/arch/x86/include/asm/trampoline.h +++ b/arch/x86/include/asm/trampoline.h @@ -22,8 +22,8 @@ extern unsigned long setup_trampoline(void); extern void __init setup_trampoline_page_table(void); extern void __init reserve_trampoline_memory(void); #else -static inline void reserve_trampoline_memory(void) {}; -extern void __init setup_trampoline_page_table(void) {}; +static inline void setup_trampoline_page_table(void) {} +static inline void reserve_trampoline_memory(void) {} #endif /* CONFIG_X86_TRAMPOLINE */ #endif /* __ASSEMBLY__ */ -- cgit v0.10.2 From 37c6c9b0e941fbb7f37a93d36abaf5fcafea87a8 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 11 Aug 2010 10:04:43 -0700 Subject: drm/i915: add panel reset workaround Ironlake requires that we clear the reset panel bit during power sequences and restore it afterwards. Uncondtionally add code to do that since it should be harmless on SNB+. Signed-off-by: Jesse Barnes diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index c6629bd..d1b4ece 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -765,6 +765,12 @@ static void ironlake_edp_panel_on (struct drm_device *dev) return; pp = I915_READ(PCH_PP_CONTROL); + + /* ILK workaround: disable reset around power sequence */ + pp &= ~PANEL_POWER_RESET; + I915_WRITE(PCH_PP_CONTROL, pp); + POSTING_READ(PCH_PP_CONTROL); + pp |= PANEL_UNLOCK_REGS | POWER_TARGET_ON; I915_WRITE(PCH_PP_CONTROL, pp); @@ -773,7 +779,9 @@ static void ironlake_edp_panel_on (struct drm_device *dev) I915_READ(PCH_PP_STATUS)); pp &= ~(PANEL_UNLOCK_REGS | EDP_FORCE_VDD); + pp |= PANEL_POWER_RESET; /* restore panel reset bit */ I915_WRITE(PCH_PP_CONTROL, pp); + POSTING_READ(PCH_PP_CONTROL); } static void ironlake_edp_panel_off (struct drm_device *dev) @@ -782,6 +790,12 @@ static void ironlake_edp_panel_off (struct drm_device *dev) u32 pp; pp = I915_READ(PCH_PP_CONTROL); + + /* ILK workaround: disable reset around power sequence */ + pp &= ~PANEL_POWER_RESET; + I915_WRITE(PCH_PP_CONTROL, pp); + POSTING_READ(PCH_PP_CONTROL); + pp &= ~POWER_TARGET_ON; I915_WRITE(PCH_PP_CONTROL, pp); @@ -790,8 +804,9 @@ static void ironlake_edp_panel_off (struct drm_device *dev) I915_READ(PCH_PP_STATUS)); /* Make sure VDD is enabled so DP AUX will work */ - pp |= EDP_FORCE_VDD; + pp |= EDP_FORCE_VDD | PANEL_POWER_RESET; /* restore panel reset bit */ I915_WRITE(PCH_PP_CONTROL, pp); + POSTING_READ(PCH_PP_CONTROL); } static void ironlake_edp_backlight_on (struct drm_device *dev) -- cgit v0.10.2 From 7643a7fa16edf180d593f705f4fa5930c40e8d2d Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 11 Aug 2010 10:06:44 -0700 Subject: drm/i915: eDP mode set sequence corrections We should disable the panel first when shutting down an eDP link. And when turning one on, the panel needs to be enabled before link training or eDP I/O won't be enabled. Signed-off-by: Jesse Barnes diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index d1b4ece..8061a48 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -840,20 +840,19 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) uint32_t dp_reg = I915_READ(intel_dp->output_reg); if (mode != DRM_MODE_DPMS_ON) { - if (dp_reg & DP_PORT_EN) { - intel_dp_link_down(intel_dp); - if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) { - ironlake_edp_backlight_off(dev); - ironlake_edp_panel_off(dev); - } + if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) { + ironlake_edp_backlight_off(dev); + ironlake_edp_panel_off(dev); } + if (dp_reg & DP_PORT_EN) + intel_dp_link_down(intel_dp); } else { if (!(dp_reg & DP_PORT_EN)) { - intel_dp_link_train(intel_dp); - if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) { + if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) ironlake_edp_panel_on(dev); + intel_dp_link_train(intel_dp); + if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) ironlake_edp_backlight_on(dev); - } } } intel_dp->dpms_mode = mode; -- cgit v0.10.2 From 9cce37f4855a30cc7c364edf18522282782f7ddc Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 13 Aug 2010 15:11:26 -0700 Subject: drm/i915: fix VGA plane disable for Ironlake+ We need to use I/O port instructions to access VGA registers on Ironlake+, and it doesn't hurt on other platforms, so switch the VGA plane disable function over to using them. Move it to init time as well while we're at it, no need to repeatedly disable the VGA plane with every mode set and DPMS event. Signed-off-by: Jesse Barnes diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 149c18b..fbe42f0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "drmP.h" #include "intel_drv.h" #include "i915_drm.h" @@ -1621,29 +1622,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return 0; } -/* Disable the VGA plane that we never use */ -static void i915_disable_vga (struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u8 sr1; - u32 vga_reg; - - if (HAS_PCH_SPLIT(dev)) - vga_reg = CPU_VGACNTRL; - else - vga_reg = VGACNTRL; - - if (I915_READ(vga_reg) & VGA_DISP_DISABLE) - return; - - I915_WRITE8(VGA_SR_INDEX, 1); - sr1 = I915_READ8(VGA_SR_DATA); - I915_WRITE8(VGA_SR_DATA, sr1 | (1 << 5)); - udelay(100); - - I915_WRITE(vga_reg, VGA_DISP_DISABLE); -} - static void ironlake_disable_pll_edp (struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -2156,8 +2134,6 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) dev_priv->display.disable_fbc) dev_priv->display.disable_fbc(dev); - i915_disable_vga(dev); - /* disable cpu pipe, disable after all planes disabled */ temp = I915_READ(pipeconf_reg); if ((temp & PIPEACONF_ENABLE) != 0) { @@ -2391,9 +2367,6 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) dev_priv->display.disable_fbc) dev_priv->display.disable_fbc(dev); - /* Disable the VGA plane that we never use */ - i915_disable_vga(dev); - /* Disable display plane */ temp = I915_READ(dspcntr_reg); if ((temp & DISPLAY_PLANE_ENABLE) != 0) { @@ -6002,6 +5975,29 @@ static void intel_init_quirks(struct drm_device *dev) } } +/* Disable the VGA plane that we never use */ +static void i915_disable_vga(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u8 sr1; + u32 vga_reg; + + if (HAS_PCH_SPLIT(dev)) + vga_reg = CPU_VGACNTRL; + else + vga_reg = VGACNTRL; + + vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO); + outb(1, VGA_SR_INDEX); + sr1 = inb(VGA_SR_DATA); + outb(sr1 | 1<<5, VGA_SR_DATA); + vga_put(dev->pdev, VGA_RSRC_LEGACY_IO); + udelay(300); + + I915_WRITE(vga_reg, VGA_DISP_DISABLE); + POSTING_READ(vga_reg); +} + void intel_modeset_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -6050,6 +6046,9 @@ void intel_modeset_init(struct drm_device *dev) intel_init_clock_gating(dev); + /* Just disable it once at startup */ + i915_disable_vga(dev); + if (IS_IRONLAKE_M(dev)) { ironlake_enable_drps(dev); intel_init_emon(dev); -- cgit v0.10.2 From d240f20f545fa4ed78ce48d1eb62ab529f2b1467 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 13 Aug 2010 15:43:26 -0700 Subject: drm/i915: make sure eDP PLL is enabled at the right time We need to make sure the eDP PLL is enabled before the pipes or planes, so do it as part of the DP prepare mode set function. Signed-off-by: Jesse Barnes diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fbe42f0..14c45b1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1622,32 +1622,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return 0; } -static void ironlake_disable_pll_edp (struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - u32 dpa_ctl; - - DRM_DEBUG_KMS("\n"); - dpa_ctl = I915_READ(DP_A); - dpa_ctl &= ~DP_PLL_ENABLE; - I915_WRITE(DP_A, dpa_ctl); -} - -static void ironlake_enable_pll_edp (struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - u32 dpa_ctl; - - dpa_ctl = I915_READ(DP_A); - dpa_ctl |= DP_PLL_ENABLE; - I915_WRITE(DP_A, dpa_ctl); - POSTING_READ(DP_A); - udelay(200); -} - - static void ironlake_set_pll_edp (struct drm_crtc *crtc, int clock) { struct drm_device *dev = crtc->dev; @@ -1940,10 +1914,7 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) } } - if (HAS_eDP) { - /* enable eDP PLL */ - ironlake_enable_pll_edp(crtc); - } else { + if (!HAS_eDP) { /* enable PCH FDI RX PLL, wait warmup plus DMI latency */ temp = I915_READ(fdi_rx_reg); @@ -2242,10 +2213,6 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) I915_WRITE(pch_dpll_reg, temp & ~DPLL_VCO_ENABLE); I915_READ(pch_dpll_reg); - if (HAS_eDP) { - ironlake_disable_pll_edp(crtc); - } - /* Switch from PCDclk to Rawclk */ temp = I915_READ(fdi_rx_reg); temp &= ~FDI_SEL_PCDCLK; @@ -3930,9 +3897,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, dpll_reg = pch_dpll_reg; } - if (is_edp) { - ironlake_disable_pll_edp(crtc); - } else if ((dpll & DPLL_VCO_ENABLE)) { + if (!is_edp) { I915_WRITE(fp_reg, fp); I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE); I915_READ(dpll_reg); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 8061a48..caaaa8f 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -831,6 +831,60 @@ static void ironlake_edp_backlight_off (struct drm_device *dev) I915_WRITE(PCH_PP_CONTROL, pp); } +static void ironlake_edp_pll_on(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 dpa_ctl; + + DRM_DEBUG_KMS("\n"); + dpa_ctl = I915_READ(DP_A); + dpa_ctl &= ~DP_PLL_ENABLE; + I915_WRITE(DP_A, dpa_ctl); +} + +static void ironlake_edp_pll_off(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 dpa_ctl; + + dpa_ctl = I915_READ(DP_A); + dpa_ctl |= DP_PLL_ENABLE; + I915_WRITE(DP_A, dpa_ctl); + udelay(200); +} + +static void intel_dp_prepare(struct drm_encoder *encoder) +{ + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t dp_reg = I915_READ(intel_dp->output_reg); + + if (IS_eDP(intel_dp)) { + ironlake_edp_backlight_off(dev); + ironlake_edp_panel_on(dev); + ironlake_edp_pll_on(encoder); + } + if (dp_reg & DP_PORT_EN) + intel_dp_link_down(intel_dp); +} + +static void intel_dp_commit(struct drm_encoder *encoder) +{ + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t dp_reg = I915_READ(intel_dp->output_reg); + + if (!(dp_reg & DP_PORT_EN)) { + intel_dp_link_train(intel_dp); + } + if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) + ironlake_edp_backlight_on(dev); +} + static void intel_dp_dpms(struct drm_encoder *encoder, int mode) { @@ -846,6 +900,8 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) } if (dp_reg & DP_PORT_EN) intel_dp_link_down(intel_dp); + if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) + ironlake_edp_pll_off(encoder); } else { if (!(dp_reg & DP_PORT_EN)) { if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) @@ -1427,9 +1483,9 @@ intel_dp_destroy (struct drm_connector *connector) static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = { .dpms = intel_dp_dpms, .mode_fixup = intel_dp_mode_fixup, - .prepare = intel_encoder_prepare, + .prepare = intel_dp_prepare, .mode_set = intel_dp_mode_set, - .commit = intel_encoder_commit, + .commit = intel_dp_commit, }; static const struct drm_connector_funcs intel_dp_connector_funcs = { -- cgit v0.10.2 From 5db5584441c2dceb75696fb31a44ac7b9b925359 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 11 Aug 2010 19:11:19 -0700 Subject: drivers/net/wireless: Restore upper case words in wiphy_ messages Commit c96c31e499b70964cfc88744046c998bb710e4b8 "(drivers/net/wireless: Use wiphy_)" inadvertently changed some upper case words to lower case. Restore the original case. Signed-off-by: Joe Perches Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index a105087..f9aa1bc 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -732,7 +732,7 @@ static int adm8211_rf_set_channel(struct ieee80211_hw *dev, unsigned int chan) /* Nothing to do for ADMtek BBP */ } else if (priv->bbp_type != ADM8211_TYPE_ADMTEK) - wiphy_debug(dev->wiphy, "unsupported bbp type %d\n", + wiphy_debug(dev->wiphy, "unsupported BBP type %d\n", priv->bbp_type); ADM8211_RESTORE(); @@ -1032,7 +1032,7 @@ static int adm8211_hw_init_bbp(struct ieee80211_hw *dev) break; } } else - wiphy_debug(dev->wiphy, "unsupported bbp %d\n", priv->bbp_type); + wiphy_debug(dev->wiphy, "unsupported BBP %d\n", priv->bbp_type); ADM8211_CSR_WRITE(SYNRF, 0); @@ -1525,7 +1525,7 @@ static int adm8211_start(struct ieee80211_hw *dev) retval = request_irq(priv->pdev->irq, adm8211_interrupt, IRQF_SHARED, "adm8211", dev); if (retval) { - wiphy_err(dev->wiphy, "failed to register irq handler\n"); + wiphy_err(dev->wiphy, "failed to register IRQ handler\n"); goto fail; } @@ -1902,7 +1902,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, goto err_free_eeprom; } - wiphy_info(dev->wiphy, "hwaddr %pm, rev 0x%02x\n", + wiphy_info(dev->wiphy, "hwaddr %pM, Rev 0x%02x\n", dev->wiphy->perm_addr, pdev->revision); return 0; diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index d5140a8..1128fa8 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -655,7 +655,7 @@ static int at76_get_hw_config(struct at76_priv *priv) exit: kfree(hwcfg); if (ret < 0) - wiphy_err(priv->hw->wiphy, "cannot get hw config (error %d)\n", + wiphy_err(priv->hw->wiphy, "cannot get HW Config (error %d)\n", ret); return ret; @@ -960,7 +960,7 @@ static void at76_dump_mib_mac_addr(struct at76_priv *priv) sizeof(struct mib_mac_addr)); if (ret < 0) { wiphy_err(priv->hw->wiphy, - "at76_get_mib (mac_addr) failed: %d\n", ret); + "at76_get_mib (MAC_ADDR) failed: %d\n", ret); goto exit; } @@ -989,7 +989,7 @@ static void at76_dump_mib_mac_wep(struct at76_priv *priv) sizeof(struct mib_mac_wep)); if (ret < 0) { wiphy_err(priv->hw->wiphy, - "at76_get_mib (mac_wep) failed: %d\n", ret); + "at76_get_mib (MAC_WEP) failed: %d\n", ret); goto exit; } @@ -1026,7 +1026,7 @@ static void at76_dump_mib_mac_mgmt(struct at76_priv *priv) sizeof(struct mib_mac_mgmt)); if (ret < 0) { wiphy_err(priv->hw->wiphy, - "at76_get_mib (mac_mgmt) failed: %d\n", ret); + "at76_get_mib (MAC_MGMT) failed: %d\n", ret); goto exit; } @@ -1062,7 +1062,7 @@ static void at76_dump_mib_mac(struct at76_priv *priv) ret = at76_get_mib(priv->udev, MIB_MAC, m, sizeof(struct mib_mac)); if (ret < 0) { wiphy_err(priv->hw->wiphy, - "at76_get_mib (mac) failed: %d\n", ret); + "at76_get_mib (MAC) failed: %d\n", ret); goto exit; } @@ -1099,7 +1099,7 @@ static void at76_dump_mib_phy(struct at76_priv *priv) ret = at76_get_mib(priv->udev, MIB_PHY, m, sizeof(struct mib_phy)); if (ret < 0) { wiphy_err(priv->hw->wiphy, - "at76_get_mib (phy) failed: %d\n", ret); + "at76_get_mib (PHY) failed: %d\n", ret); goto exit; } @@ -1132,7 +1132,7 @@ static void at76_dump_mib_local(struct at76_priv *priv) ret = at76_get_mib(priv->udev, MIB_LOCAL, m, sizeof(struct mib_local)); if (ret < 0) { wiphy_err(priv->hw->wiphy, - "at76_get_mib (local) failed: %d\n", ret); + "at76_get_mib (LOCAL) failed: %d\n", ret); goto exit; } @@ -1158,7 +1158,7 @@ static void at76_dump_mib_mdomain(struct at76_priv *priv) sizeof(struct mib_mdomain)); if (ret < 0) { wiphy_err(priv->hw->wiphy, - "at76_get_mib (mdomain) failed: %d\n", ret); + "at76_get_mib (MDOMAIN) failed: %d\n", ret); goto exit; } @@ -1229,7 +1229,7 @@ static int at76_submit_rx_urb(struct at76_priv *priv) struct sk_buff *skb = priv->rx_skb; if (!priv->rx_urb) { - wiphy_err(priv->hw->wiphy, "%s: priv->rx_urb is null\n", + wiphy_err(priv->hw->wiphy, "%s: priv->rx_urb is NULL\n", __func__); return -EFAULT; } @@ -1792,7 +1792,7 @@ static int at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb) wiphy_err(priv->hw->wiphy, "error in tx submit urb: %d\n", ret); if (ret == -EINVAL) wiphy_err(priv->hw->wiphy, - "-einval: tx urb %p hcpriv %p complete %p\n", + "-EINVAL: tx urb %p hcpriv %p complete %p\n", priv->tx_urb, priv->tx_urb->hcpriv, priv->tx_urb->complete); } @@ -2310,7 +2310,7 @@ static int at76_init_new_device(struct at76_priv *priv, priv->mac80211_registered = 1; - wiphy_info(priv->hw->wiphy, "usb %s, mac %pm, firmware %d.%d.%d-%d\n", + wiphy_info(priv->hw->wiphy, "USB %s, MAC %pM, firmware %d.%d.%d-%d\n", dev_name(&interface->dev), priv->mac_addr, priv->fw_version.major, priv->fw_version.minor, priv->fw_version.patch, priv->fw_version.build); diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index c67b05f..debfb0f 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -245,7 +245,7 @@ static void __ar9170_dump_txstats(struct ar9170 *ar) { int i; - wiphy_debug(ar->hw->wiphy, "qos queue stats\n"); + wiphy_debug(ar->hw->wiphy, "QoS queue stats\n"); for (i = 0; i < __AR9170_NUM_TXQ; i++) wiphy_debug(ar->hw->wiphy, @@ -387,7 +387,7 @@ static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar, if (mac && compare_ether_addr(ieee80211_get_DA(hdr), mac)) { #ifdef AR9170_QUEUE_DEBUG wiphy_debug(ar->hw->wiphy, - "skip frame => da %pm != %pm\n", + "skip frame => DA %pM != %pM\n", mac, ieee80211_get_DA(hdr)); ar9170_print_txheader(ar, skb); #endif /* AR9170_QUEUE_DEBUG */ diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 01ad7f7..86fa8ab 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -486,7 +486,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, struct ieee80211_rx_status rx_status; if (data->idle) { - wiphy_debug(hw->wiphy, "trying to tx when idle - reject\n"); + wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n"); return false; } diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index d761ed2..f152a25 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -910,14 +910,14 @@ static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index) rxq->rxd = pci_alloc_consistent(priv->pdev, size, &rxq->rxd_dma); if (rxq->rxd == NULL) { - wiphy_err(hw->wiphy, "failed to alloc rx descriptors\n"); + wiphy_err(hw->wiphy, "failed to alloc RX descriptors\n"); return -ENOMEM; } memset(rxq->rxd, 0, size); rxq->buf = kmalloc(MWL8K_RX_DESCS * sizeof(*rxq->buf), GFP_KERNEL); if (rxq->buf == NULL) { - wiphy_err(hw->wiphy, "failed to alloc rx skbuff list\n"); + wiphy_err(hw->wiphy, "failed to alloc RX skbuff list\n"); pci_free_consistent(priv->pdev, size, rxq->rxd, rxq->rxd_dma); return -ENOMEM; } @@ -1145,14 +1145,14 @@ static int mwl8k_txq_init(struct ieee80211_hw *hw, int index) txq->txd = pci_alloc_consistent(priv->pdev, size, &txq->txd_dma); if (txq->txd == NULL) { - wiphy_err(hw->wiphy, "failed to alloc tx descriptors\n"); + wiphy_err(hw->wiphy, "failed to alloc TX descriptors\n"); return -ENOMEM; } memset(txq->txd, 0, size); txq->skb = kmalloc(MWL8K_TX_DESCS * sizeof(*txq->skb), GFP_KERNEL); if (txq->skb == NULL) { - wiphy_err(hw->wiphy, "failed to alloc tx skbuff list\n"); + wiphy_err(hw->wiphy, "failed to alloc TX skbuff list\n"); pci_free_consistent(priv->pdev, size, txq->txd, txq->txd_dma); return -ENOMEM; } @@ -1573,7 +1573,7 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) PCI_DMA_BIDIRECTIONAL); if (!timeout) { - wiphy_err(hw->wiphy, "command %s timeout after %u ms\n", + wiphy_err(hw->wiphy, "Command %s timeout after %u ms\n", mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), MWL8K_CMD_TIMEOUT_MS); rc = -ETIMEDOUT; @@ -1584,11 +1584,11 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) rc = cmd->result ? -EINVAL : 0; if (rc) - wiphy_err(hw->wiphy, "command %s error 0x%x\n", + wiphy_err(hw->wiphy, "Command %s error 0x%x\n", mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), le16_to_cpu(cmd->result)); else if (ms > 2000) - wiphy_notice(hw->wiphy, "command %s took %d ms\n", + wiphy_notice(hw->wiphy, "Command %s took %d ms\n", mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), ms); @@ -3210,7 +3210,7 @@ static int mwl8k_start(struct ieee80211_hw *hw) rc = request_irq(priv->pdev->irq, mwl8k_interrupt, IRQF_SHARED, MWL8K_NAME, hw); if (rc) { - wiphy_err(hw->wiphy, "failed to register irq handler\n"); + wiphy_err(hw->wiphy, "failed to register IRQ handler\n"); return -EIO; } @@ -3926,7 +3926,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, priv->sram = pci_iomap(pdev, 0, 0x10000); if (priv->sram == NULL) { - wiphy_err(hw->wiphy, "cannot map device sram\n"); + wiphy_err(hw->wiphy, "Cannot map device SRAM\n"); goto err_iounmap; } @@ -3938,7 +3938,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, if (priv->regs == NULL) { priv->regs = pci_iomap(pdev, 2, 0x10000); if (priv->regs == NULL) { - wiphy_err(hw->wiphy, "cannot map device registers\n"); + wiphy_err(hw->wiphy, "Cannot map device registers\n"); goto err_iounmap; } } @@ -3950,14 +3950,14 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, /* Ask userland hotplug daemon for the device firmware */ rc = mwl8k_request_firmware(priv); if (rc) { - wiphy_err(hw->wiphy, "firmware files not found\n"); + wiphy_err(hw->wiphy, "Firmware files not found\n"); goto err_stop_firmware; } /* Load firmware into hardware */ rc = mwl8k_load_firmware(hw); if (rc) { - wiphy_err(hw->wiphy, "cannot start firmware\n"); + wiphy_err(hw->wiphy, "Cannot start firmware\n"); goto err_stop_firmware; } @@ -4047,7 +4047,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, rc = request_irq(priv->pdev->irq, mwl8k_interrupt, IRQF_SHARED, MWL8K_NAME, hw); if (rc) { - wiphy_err(hw->wiphy, "failed to register irq handler\n"); + wiphy_err(hw->wiphy, "failed to register IRQ handler\n"); goto err_free_queues; } @@ -4067,7 +4067,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, rc = mwl8k_cmd_get_hw_spec_sta(hw); } if (rc) { - wiphy_err(hw->wiphy, "cannot initialise firmware\n"); + wiphy_err(hw->wiphy, "Cannot initialise firmware\n"); goto err_free_irq; } @@ -4081,14 +4081,14 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, /* Turn radio off */ rc = mwl8k_cmd_radio_disable(hw); if (rc) { - wiphy_err(hw->wiphy, "cannot disable\n"); + wiphy_err(hw->wiphy, "Cannot disable\n"); goto err_free_irq; } /* Clear MAC address */ rc = mwl8k_cmd_set_mac_addr(hw, NULL, "\x00\x00\x00\x00\x00\x00"); if (rc) { - wiphy_err(hw->wiphy, "cannot clear mac address\n"); + wiphy_err(hw->wiphy, "Cannot clear MAC address\n"); goto err_free_irq; } @@ -4098,7 +4098,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, rc = ieee80211_register_hw(hw); if (rc) { - wiphy_err(hw->wiphy, "cannot register device\n"); + wiphy_err(hw->wiphy, "Cannot register device\n"); goto err_free_queues; } diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c index d687cb7..78347041 100644 --- a/drivers/net/wireless/p54/eeprom.c +++ b/drivers/net/wireless/p54/eeprom.c @@ -167,7 +167,7 @@ static int p54_generate_band(struct ieee80211_hw *dev, } if (j == 0) { - wiphy_err(dev->wiphy, "disabling totally damaged %d GHz band\n", + wiphy_err(dev->wiphy, "Disabling totally damaged %d GHz band\n", (band == IEEE80211_BAND_2GHZ) ? 2 : 5); ret = -ENODATA; @@ -695,12 +695,12 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) u8 perm_addr[ETH_ALEN]; wiphy_warn(dev->wiphy, - "invalid hwaddr! using randomly generated mac addr\n"); + "Invalid hwaddr! Using randomly generated MAC addr\n"); random_ether_addr(perm_addr); SET_IEEE80211_PERM_ADDR(dev, perm_addr); } - wiphy_info(dev->wiphy, "hwaddr %pm, mac:isl38%02x rf:%s\n", + wiphy_info(dev->wiphy, "hwaddr %pM, MAC:isl38%02x RF:%s\n", dev->wiphy->perm_addr, priv->version, p54_rf_chips[priv->rxhw]); diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c index 47006bc..15b20c2 100644 --- a/drivers/net/wireless/p54/fwio.c +++ b/drivers/net/wireless/p54/fwio.c @@ -125,7 +125,7 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) if (fw_version) wiphy_info(priv->hw->wiphy, - "fw rev %s - softmac protocol %x.%x\n", + "FW rev %s - Softmac protocol %x.%x\n", fw_version, priv->fw_var >> 8, priv->fw_var & 0xff); if (priv->fw_var < 0x500) diff --git a/drivers/net/wireless/p54/led.c b/drivers/net/wireless/p54/led.c index ea91f5c..3837e1e 100644 --- a/drivers/net/wireless/p54/led.c +++ b/drivers/net/wireless/p54/led.c @@ -58,7 +58,7 @@ static void p54_update_leds(struct work_struct *work) err = p54_set_leds(priv); if (err && net_ratelimit()) wiphy_err(priv->hw->wiphy, - "failed to update leds (%d).\n", err); + "failed to update LEDs (%d).\n", err); if (rerun) ieee80211_queue_delayed_work(priv->hw, &priv->led_work, @@ -103,7 +103,7 @@ static int p54_register_led(struct p54_common *priv, err = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_dev); if (err) wiphy_err(priv->hw->wiphy, - "failed to register %s led.\n", name); + "Failed to register %s LED.\n", name); else led->registered = 1; diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index 822f8dc..1eacba4 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -466,7 +466,7 @@ static int p54p_open(struct ieee80211_hw *dev) P54P_READ(dev_int); if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) { - wiphy_err(dev->wiphy, "cannot boot firmware!\n"); + wiphy_err(dev->wiphy, "Cannot boot firmware!\n"); p54p_stop(dev); return -ETIMEDOUT; } diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 427b46f..173aec3 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -540,7 +540,7 @@ static void p54_rx_trap(struct p54_common *priv, struct sk_buff *skb) case P54_TRAP_BEACON_TX: break; case P54_TRAP_RADAR: - wiphy_info(priv->hw->wiphy, "radar (freq:%d mhz)\n", freq); + wiphy_info(priv->hw->wiphy, "radar (freq:%d MHz)\n", freq); break; case P54_TRAP_NO_BEACON: if (priv->vif) diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c index b50c39a..30107ce 100644 --- a/drivers/net/wireless/rtl818x/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -445,7 +445,7 @@ static int rtl8180_init_rx_ring(struct ieee80211_hw *dev) &priv->rx_ring_dma); if (!priv->rx_ring || (unsigned long)priv->rx_ring & 0xFF) { - wiphy_err(dev->wiphy, "cannot allocate rx ring\n"); + wiphy_err(dev->wiphy, "Cannot allocate RX ring\n"); return -ENOMEM; } @@ -502,7 +502,7 @@ static int rtl8180_init_tx_ring(struct ieee80211_hw *dev, ring = pci_alloc_consistent(priv->pdev, sizeof(*ring) * entries, &dma); if (!ring || (unsigned long)ring & 0xFF) { - wiphy_err(dev->wiphy, "cannot allocate tx ring (prio = %d)\n", + wiphy_err(dev->wiphy, "Cannot allocate TX ring (prio = %d)\n", prio); return -ENOMEM; } @@ -568,7 +568,7 @@ static int rtl8180_start(struct ieee80211_hw *dev) ret = request_irq(priv->pdev->irq, rtl8180_interrupt, IRQF_SHARED, KBUILD_MODNAME, dev); if (ret) { - wiphy_err(dev->wiphy, "failed to register irq handler\n"); + wiphy_err(dev->wiphy, "failed to register IRQ handler\n"); goto err_free_rings; } diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 5738a55..98e0351 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -573,7 +573,7 @@ static int rtl8187_cmd_reset(struct ieee80211_hw *dev) } while (--i); if (!i) { - wiphy_err(dev->wiphy, "reset timeout!\n"); + wiphy_err(dev->wiphy, "Reset timeout!\n"); return -ETIMEDOUT; } @@ -1526,7 +1526,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, mutex_init(&priv->conf_mutex); skb_queue_head_init(&priv->b_tx_status.queue); - wiphy_info(dev->wiphy, "hwaddr %pm, %s v%d + %s, rfkill mask %d\n", + wiphy_info(dev->wiphy, "hwaddr %pM, %s V%d + %s, rfkill mask %d\n", mac_addr, chip_name, priv->asic_rev, priv->rf->name, priv->rfkill_mask); diff --git a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c index fd96f91..97eebdc 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c +++ b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c @@ -366,7 +366,7 @@ static void rtl8225_rf_init(struct ieee80211_hw *dev) rtl8225_write(dev, 0x02, 0x044d); msleep(100); if (!(rtl8225_read(dev, 6) & (1 << 7))) - wiphy_warn(dev->wiphy, "rf calibration failed! %x\n", + wiphy_warn(dev->wiphy, "RF Calibration Failed! %x\n", rtl8225_read(dev, 6)); } @@ -735,7 +735,7 @@ static void rtl8225z2_rf_init(struct ieee80211_hw *dev) rtl8225_write(dev, 0x02, 0x044D); msleep(100); if (!(rtl8225_read(dev, 6) & (1 << 7))) - wiphy_warn(dev->wiphy, "rf calibration failed! %x\n", + wiphy_warn(dev->wiphy, "RF Calibration Failed! %x\n", rtl8225_read(dev, 6)); } -- cgit v0.10.2 From 6a017e043a8c5e4f1e7c1152bc6477da8066f5f6 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 18 Aug 2010 12:53:28 -0700 Subject: iwlwifi: use long monitor timer for 5300 series For 5000 series of devices, use long monitor timer to check stuck tx queues. This modification apply to all the 5000 series including 5300 and others. Cc: stable@kernel.org [2.6.35] Reported-by: drago01 Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 0cbefa3..48bdcd8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -663,7 +663,7 @@ struct iwl_cfg iwl5150_agn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -693,7 +693,7 @@ struct iwl_cfg iwl5150_abg_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, -- cgit v0.10.2 From 6ec274750c99448c3412bbc10c97ce0c993f8a4e Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Wed, 18 Aug 2010 08:03:37 +0000 Subject: sparc64: simple microoptimizations for atomic functions Simple microoptimizations for sparc64 atomic functions: Save one instruction by using a delay slot. Use %g1 instead of %g7, because %g1 is written earlier. Signed-off-by: Mikulas Patocka Signed-off-by: David S. Miller diff --git a/arch/sparc/lib/atomic_64.S b/arch/sparc/lib/atomic_64.S index 0268210..703c9c3 100644 --- a/arch/sparc/lib/atomic_64.S +++ b/arch/sparc/lib/atomic_64.S @@ -52,10 +52,9 @@ atomic_add_ret: /* %o0 = increment, %o1 = atomic_ptr */ cas [%o1], %g1, %g7 cmp %g1, %g7 bne,pn %icc, 2f - add %g7, %o0, %g7 - sra %g7, 0, %o0 + add %g1, %o0, %g1 retl - nop + sra %g1, 0, %o0 2: BACKOFF_SPIN(%o2, %o3, 1b) .size atomic_add_ret, .-atomic_add_ret @@ -68,10 +67,9 @@ atomic_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */ cas [%o1], %g1, %g7 cmp %g1, %g7 bne,pn %icc, 2f - sub %g7, %o0, %g7 - sra %g7, 0, %o0 + sub %g1, %o0, %g1 retl - nop + sra %g1, 0, %o0 2: BACKOFF_SPIN(%o2, %o3, 1b) .size atomic_sub_ret, .-atomic_sub_ret @@ -114,10 +112,9 @@ atomic64_add_ret: /* %o0 = increment, %o1 = atomic_ptr */ casx [%o1], %g1, %g7 cmp %g1, %g7 bne,pn %xcc, 2f - add %g7, %o0, %g7 - mov %g7, %o0 - retl nop + retl + add %g1, %o0, %o0 2: BACKOFF_SPIN(%o2, %o3, 1b) .size atomic64_add_ret, .-atomic64_add_ret @@ -130,9 +127,8 @@ atomic64_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */ casx [%o1], %g1, %g7 cmp %g1, %g7 bne,pn %xcc, 2f - sub %g7, %o0, %g7 - mov %g7, %o0 - retl nop + retl + sub %g1, %o0, %o0 2: BACKOFF_SPIN(%o2, %o3, 1b) .size atomic64_sub_ret, .-atomic64_sub_ret -- cgit v0.10.2 From 0f58189d4a3ca96d7959501ecb203177efdbc5bd Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 18 Aug 2010 22:53:26 -0700 Subject: sparc64: Make lock backoff really a NOP on UP builds. As noticed by Mikulas Patocka, the backoff macros don't completely nop out for UP builds, we still get a branch always and a delay slot nop. Fix this by making the branch to the backoff spin loop selective, then we can nop out the spin loop completely. Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/backoff.h b/arch/sparc/include/asm/backoff.h index fa1fdf6..db3af0d 100644 --- a/arch/sparc/include/asm/backoff.h +++ b/arch/sparc/include/asm/backoff.h @@ -8,6 +8,9 @@ #define BACKOFF_SETUP(reg) \ mov 1, reg +#define BACKOFF_LABEL(spin_label, continue_label) \ + spin_label + #define BACKOFF_SPIN(reg, tmp, label) \ mov reg, tmp; \ 88: brnz,pt tmp, 88b; \ @@ -22,9 +25,11 @@ #else #define BACKOFF_SETUP(reg) -#define BACKOFF_SPIN(reg, tmp, label) \ - ba,pt %xcc, label; \ - nop; + +#define BACKOFF_LABEL(spin_label, continue_label) \ + continue_label + +#define BACKOFF_SPIN(reg, tmp, label) #endif diff --git a/arch/sparc/lib/atomic_64.S b/arch/sparc/lib/atomic_64.S index 703c9c3..59186e0 100644 --- a/arch/sparc/lib/atomic_64.S +++ b/arch/sparc/lib/atomic_64.S @@ -21,7 +21,7 @@ atomic_add: /* %o0 = increment, %o1 = atomic_ptr */ add %g1, %o0, %g7 cas [%o1], %g1, %g7 cmp %g1, %g7 - bne,pn %icc, 2f + bne,pn %icc, BACKOFF_LABEL(2f, 1b) nop retl nop @@ -36,7 +36,7 @@ atomic_sub: /* %o0 = decrement, %o1 = atomic_ptr */ sub %g1, %o0, %g7 cas [%o1], %g1, %g7 cmp %g1, %g7 - bne,pn %icc, 2f + bne,pn %icc, BACKOFF_LABEL(2f, 1b) nop retl nop @@ -51,7 +51,7 @@ atomic_add_ret: /* %o0 = increment, %o1 = atomic_ptr */ add %g1, %o0, %g7 cas [%o1], %g1, %g7 cmp %g1, %g7 - bne,pn %icc, 2f + bne,pn %icc, BACKOFF_LABEL(2f, 1b) add %g1, %o0, %g1 retl sra %g1, 0, %o0 @@ -66,7 +66,7 @@ atomic_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */ sub %g1, %o0, %g7 cas [%o1], %g1, %g7 cmp %g1, %g7 - bne,pn %icc, 2f + bne,pn %icc, BACKOFF_LABEL(2f, 1b) sub %g1, %o0, %g1 retl sra %g1, 0, %o0 @@ -81,7 +81,7 @@ atomic64_add: /* %o0 = increment, %o1 = atomic_ptr */ add %g1, %o0, %g7 casx [%o1], %g1, %g7 cmp %g1, %g7 - bne,pn %xcc, 2f + bne,pn %xcc, BACKOFF_LABEL(2f, 1b) nop retl nop @@ -96,7 +96,7 @@ atomic64_sub: /* %o0 = decrement, %o1 = atomic_ptr */ sub %g1, %o0, %g7 casx [%o1], %g1, %g7 cmp %g1, %g7 - bne,pn %xcc, 2f + bne,pn %xcc, BACKOFF_LABEL(2f, 1b) nop retl nop @@ -111,7 +111,7 @@ atomic64_add_ret: /* %o0 = increment, %o1 = atomic_ptr */ add %g1, %o0, %g7 casx [%o1], %g1, %g7 cmp %g1, %g7 - bne,pn %xcc, 2f + bne,pn %xcc, BACKOFF_LABEL(2f, 1b) nop retl add %g1, %o0, %o0 @@ -126,7 +126,7 @@ atomic64_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */ sub %g1, %o0, %g7 casx [%o1], %g1, %g7 cmp %g1, %g7 - bne,pn %xcc, 2f + bne,pn %xcc, BACKOFF_LABEL(2f, 1b) nop retl sub %g1, %o0, %o0 diff --git a/arch/sparc/lib/bitops.S b/arch/sparc/lib/bitops.S index 2b7228c..3dc61d5 100644 --- a/arch/sparc/lib/bitops.S +++ b/arch/sparc/lib/bitops.S @@ -22,7 +22,7 @@ test_and_set_bit: /* %o0=nr, %o1=addr */ or %g7, %o2, %g1 casx [%o1], %g7, %g1 cmp %g7, %g1 - bne,pn %xcc, 2f + bne,pn %xcc, BACKOFF_LABEL(2f, 1b) and %g7, %o2, %g2 clr %o0 movrne %g2, 1, %o0 @@ -45,7 +45,7 @@ test_and_clear_bit: /* %o0=nr, %o1=addr */ andn %g7, %o2, %g1 casx [%o1], %g7, %g1 cmp %g7, %g1 - bne,pn %xcc, 2f + bne,pn %xcc, BACKOFF_LABEL(2f, 1b) and %g7, %o2, %g2 clr %o0 movrne %g2, 1, %o0 @@ -68,7 +68,7 @@ test_and_change_bit: /* %o0=nr, %o1=addr */ xor %g7, %o2, %g1 casx [%o1], %g7, %g1 cmp %g7, %g1 - bne,pn %xcc, 2f + bne,pn %xcc, BACKOFF_LABEL(2f, 1b) and %g7, %o2, %g2 clr %o0 movrne %g2, 1, %o0 @@ -91,7 +91,7 @@ set_bit: /* %o0=nr, %o1=addr */ or %g7, %o2, %g1 casx [%o1], %g7, %g1 cmp %g7, %g1 - bne,pn %xcc, 2f + bne,pn %xcc, BACKOFF_LABEL(2f, 1b) nop retl nop @@ -112,7 +112,7 @@ clear_bit: /* %o0=nr, %o1=addr */ andn %g7, %o2, %g1 casx [%o1], %g7, %g1 cmp %g7, %g1 - bne,pn %xcc, 2f + bne,pn %xcc, BACKOFF_LABEL(2f, 1b) nop retl nop @@ -133,7 +133,7 @@ change_bit: /* %o0=nr, %o1=addr */ xor %g7, %o2, %g1 casx [%o1], %g7, %g1 cmp %g7, %g1 - bne,pn %xcc, 2f + bne,pn %xcc, BACKOFF_LABEL(2f, 1b) nop retl nop -- cgit v0.10.2 From 4d8ec5f3b65dd64fa785192dc7ab2807916a05b2 Mon Sep 17 00:00:00 2001 From: Charles Chin Date: Thu, 19 Aug 2010 08:06:16 +0200 Subject: ALSA: hda - Add support for IDT 92HD89XX codecs Just added new codec ids. These are almost compatible with existing ones. Signed-off-by: Charles Chin Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index f3f861b..95148e5 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -6303,6 +6303,21 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = { { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx }, { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx }, { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx }, + { .id = 0x111d76c0, .name = "92HD89C3", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c1, .name = "92HD89C2", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c2, .name = "92HD89C1", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c3, .name = "92HD89B3", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c4, .name = "92HD89B2", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c5, .name = "92HD89B1", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c6, .name = "92HD89E3", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c7, .name = "92HD89E2", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c8, .name = "92HD89E1", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c9, .name = "92HD89D3", .patch = patch_stac92hd73xx }, + { .id = 0x111d76ca, .name = "92HD89D2", .patch = patch_stac92hd73xx }, + { .id = 0x111d76cb, .name = "92HD89D1", .patch = patch_stac92hd73xx }, + { .id = 0x111d76cc, .name = "92HD89F3", .patch = patch_stac92hd73xx }, + { .id = 0x111d76cd, .name = "92HD89F2", .patch = patch_stac92hd73xx }, + { .id = 0x111d76ce, .name = "92HD89F1", .patch = patch_stac92hd73xx }, {} /* terminator */ }; -- cgit v0.10.2 From 274714f55c023c683a6b2deedfb2209a9457f4ec Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 19 Aug 2010 08:11:53 +0200 Subject: ALSA: hda - Fix build error with CONFIG_PROC_FS=n hdmi_eld_update_pcm_info() must be always compiled in. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 803b298..26c3ade 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -596,6 +596,8 @@ void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld) } EXPORT_SYMBOL_HDA(snd_hda_eld_proc_free); +#endif /* CONFIG_PROC_FS */ + /* update PCM info based on ELD */ void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm, struct hda_pcm_stream *codec_pars) @@ -644,5 +646,3 @@ void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm, pcm->maxbps = min(pcm->maxbps, codec_pars->maxbps); } EXPORT_SYMBOL_HDA(hdmi_eld_update_pcm_info); - -#endif /* CONFIG_PROC_FS */ -- cgit v0.10.2 From 9c77b846ec8b4e0c7107dd7f820172462dc84a61 Mon Sep 17 00:00:00 2001 From: Daniel T Chen Date: Wed, 18 Aug 2010 19:33:43 -0400 Subject: ALSA: intel8x0: Mute External Amplifier by default for ThinkPad X31 BugLink: https://bugs.launchpad.net/bugs/619439 This ThinkPad model needs External Amplifier muted for audible playback, so set the inv_eapd quirk for it. Reported-and-tested-by: Dennis Bell Cc: Signed-off-by: Daniel T Chen Signed-off-by: Takashi Iwai diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 6433e65..4677492 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -1776,6 +1776,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { }, { .subvendor = 0x1014, + .subdevice = 0x0534, + .name = "ThinkPad X31", + .type = AC97_TUNE_INV_EAPD + }, + { + .subvendor = 0x1014, .subdevice = 0x1f00, .name = "MS-9128", .type = AC97_TUNE_ALC_JACK -- cgit v0.10.2 From a49f37eed22b74221f271811ea41323654e40dad Mon Sep 17 00:00:00 2001 From: Sachin Sanap Date: Fri, 13 Aug 2010 21:22:49 +0000 Subject: net: add Fast Ethernet driver for PXA168. Signed-off-by: Sachin Sanap Signed-off-by: David S. Miller diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index ebe6839..fe58156 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -928,6 +928,16 @@ config SMC91X The module will be called smc91x. If you want to compile it as a module, say M here and read . +config PXA168_ETH + tristate "Marvell pxa168 ethernet support" + depends on CPU_PXA168 + select PHYLIB + help + This driver supports the pxa168 Ethernet ports. + + To compile this driver as a module, choose M here. The module + will be called pxa168_eth. + config NET_NETX tristate "NetX Ethernet support" select MII diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 56e8c27..3e8f150 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -244,6 +244,7 @@ obj-$(CONFIG_MYRI10GE) += myri10ge/ obj-$(CONFIG_SMC91X) += smc91x.o obj-$(CONFIG_SMC911X) += smc911x.o obj-$(CONFIG_SMSC911X) += smsc911x.o +obj-$(CONFIG_PXA168_ETH) += pxa168_eth.o obj-$(CONFIG_BFIN_MAC) += bfin_mac.o obj-$(CONFIG_DM9000) += dm9000.o obj-$(CONFIG_PASEMI_MAC) += pasemi_mac_driver.o diff --git a/drivers/net/pxa168_eth.c b/drivers/net/pxa168_eth.c new file mode 100644 index 0000000..ecc64d7 --- /dev/null +++ b/drivers/net/pxa168_eth.c @@ -0,0 +1,1666 @@ +/* + * PXA168 ethernet driver. + * Most of the code is derived from mv643xx ethernet driver. + * + * Copyright (C) 2010 Marvell International Ltd. + * Sachin Sanap + * Philip Rakity + * Mark Brown + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#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 "pxa168-eth" +#define DRIVER_VERSION "0.3" + +/* + * Registers + */ + +#define PHY_ADDRESS 0x0000 +#define SMI 0x0010 +#define PORT_CONFIG 0x0400 +#define PORT_CONFIG_EXT 0x0408 +#define PORT_COMMAND 0x0410 +#define PORT_STATUS 0x0418 +#define HTPR 0x0428 +#define SDMA_CONFIG 0x0440 +#define SDMA_CMD 0x0448 +#define INT_CAUSE 0x0450 +#define INT_W_CLEAR 0x0454 +#define INT_MASK 0x0458 +#define ETH_F_RX_DESC_0 0x0480 +#define ETH_C_RX_DESC_0 0x04A0 +#define ETH_C_TX_DESC_1 0x04E4 + +/* smi register */ +#define SMI_BUSY (1 << 28) /* 0 - Write, 1 - Read */ +#define SMI_R_VALID (1 << 27) /* 0 - Write, 1 - Read */ +#define SMI_OP_W (0 << 26) /* Write operation */ +#define SMI_OP_R (1 << 26) /* Read operation */ + +#define PHY_WAIT_ITERATIONS 10 + +#define PXA168_ETH_PHY_ADDR_DEFAULT 0 +/* RX & TX descriptor command */ +#define BUF_OWNED_BY_DMA (1 << 31) + +/* RX descriptor status */ +#define RX_EN_INT (1 << 23) +#define RX_FIRST_DESC (1 << 17) +#define RX_LAST_DESC (1 << 16) +#define RX_ERROR (1 << 15) + +/* TX descriptor command */ +#define TX_EN_INT (1 << 23) +#define TX_GEN_CRC (1 << 22) +#define TX_ZERO_PADDING (1 << 18) +#define TX_FIRST_DESC (1 << 17) +#define TX_LAST_DESC (1 << 16) +#define TX_ERROR (1 << 15) + +/* SDMA_CMD */ +#define SDMA_CMD_AT (1 << 31) +#define SDMA_CMD_TXDL (1 << 24) +#define SDMA_CMD_TXDH (1 << 23) +#define SDMA_CMD_AR (1 << 15) +#define SDMA_CMD_ERD (1 << 7) + +/* Bit definitions of the Port Config Reg */ +#define PCR_HS (1 << 12) +#define PCR_EN (1 << 7) +#define PCR_PM (1 << 0) + +/* Bit definitions of the Port Config Extend Reg */ +#define PCXR_2BSM (1 << 28) +#define PCXR_DSCP_EN (1 << 21) +#define PCXR_MFL_1518 (0 << 14) +#define PCXR_MFL_1536 (1 << 14) +#define PCXR_MFL_2048 (2 << 14) +#define PCXR_MFL_64K (3 << 14) +#define PCXR_FLP (1 << 11) +#define PCXR_PRIO_TX_OFF 3 +#define PCXR_TX_HIGH_PRI (7 << PCXR_PRIO_TX_OFF) + +/* Bit definitions of the SDMA Config Reg */ +#define SDCR_BSZ_OFF 12 +#define SDCR_BSZ8 (3 << SDCR_BSZ_OFF) +#define SDCR_BSZ4 (2 << SDCR_BSZ_OFF) +#define SDCR_BSZ2 (1 << SDCR_BSZ_OFF) +#define SDCR_BSZ1 (0 << SDCR_BSZ_OFF) +#define SDCR_BLMR (1 << 6) +#define SDCR_BLMT (1 << 7) +#define SDCR_RIFB (1 << 9) +#define SDCR_RC_OFF 2 +#define SDCR_RC_MAX_RETRANS (0xf << SDCR_RC_OFF) + +/* + * Bit definitions of the Interrupt Cause Reg + * and Interrupt MASK Reg is the same + */ +#define ICR_RXBUF (1 << 0) +#define ICR_TXBUF_H (1 << 2) +#define ICR_TXBUF_L (1 << 3) +#define ICR_TXEND_H (1 << 6) +#define ICR_TXEND_L (1 << 7) +#define ICR_RXERR (1 << 8) +#define ICR_TXERR_H (1 << 10) +#define ICR_TXERR_L (1 << 11) +#define ICR_TX_UDR (1 << 13) +#define ICR_MII_CH (1 << 28) + +#define ALL_INTS (ICR_TXBUF_H | ICR_TXBUF_L | ICR_TX_UDR |\ + ICR_TXERR_H | ICR_TXERR_L |\ + ICR_TXEND_H | ICR_TXEND_L |\ + ICR_RXBUF | ICR_RXERR | ICR_MII_CH) + +#define ETH_HW_IP_ALIGN 2 /* hw aligns IP header */ + +#define NUM_RX_DESCS 64 +#define NUM_TX_DESCS 64 + +#define HASH_ADD 0 +#define HASH_DELETE 1 +#define HASH_ADDR_TABLE_SIZE 0x4000 /* 16K (1/2K address - PCR_HS == 1) */ +#define HOP_NUMBER 12 + +/* Bit definitions for Port status */ +#define PORT_SPEED_100 (1 << 0) +#define FULL_DUPLEX (1 << 1) +#define FLOW_CONTROL_ENABLED (1 << 2) +#define LINK_UP (1 << 3) + +/* Bit definitions for work to be done */ +#define WORK_LINK (1 << 0) +#define WORK_TX_DONE (1 << 1) + +/* + * Misc definitions. + */ +#define SKB_DMA_REALIGN ((PAGE_SIZE - NET_SKB_PAD) % SMP_CACHE_BYTES) + +struct rx_desc { + u32 cmd_sts; /* Descriptor command status */ + u16 byte_cnt; /* Descriptor buffer byte count */ + u16 buf_size; /* Buffer size */ + u32 buf_ptr; /* Descriptor buffer pointer */ + u32 next_desc_ptr; /* Next descriptor pointer */ +}; + +struct tx_desc { + u32 cmd_sts; /* Command/status field */ + u16 reserved; + u16 byte_cnt; /* buffer byte count */ + u32 buf_ptr; /* pointer to buffer for this descriptor */ + u32 next_desc_ptr; /* Pointer to next descriptor */ +}; + +struct pxa168_eth_private { + int port_num; /* User Ethernet port number */ + + int rx_resource_err; /* Rx ring resource error flag */ + + /* Next available and first returning Rx resource */ + int rx_curr_desc_q, rx_used_desc_q; + + /* Next available and first returning Tx resource */ + int tx_curr_desc_q, tx_used_desc_q; + + struct rx_desc *p_rx_desc_area; + dma_addr_t rx_desc_dma; + int rx_desc_area_size; + struct sk_buff **rx_skb; + + struct tx_desc *p_tx_desc_area; + dma_addr_t tx_desc_dma; + int tx_desc_area_size; + struct sk_buff **tx_skb; + + struct work_struct tx_timeout_task; + + struct net_device *dev; + struct napi_struct napi; + u8 work_todo; + int skb_size; + + struct net_device_stats stats; + /* Size of Tx Ring per queue */ + int tx_ring_size; + /* Number of tx descriptors in use */ + int tx_desc_count; + /* Size of Rx Ring per queue */ + int rx_ring_size; + /* Number of rx descriptors in use */ + int rx_desc_count; + + /* + * Used in case RX Ring is empty, which can occur when + * system does not have resources (skb's) + */ + struct timer_list timeout; + struct mii_bus *smi_bus; + struct phy_device *phy; + + /* clock */ + struct clk *clk; + struct pxa168_eth_platform_data *pd; + /* + * Ethernet controller base address. + */ + void __iomem *base; + + /* Pointer to the hardware address filter table */ + void *htpr; + dma_addr_t htpr_dma; +}; + +struct addr_table_entry { + __le32 lo; + __le32 hi; +}; + +/* Bit fields of a Hash Table Entry */ +enum hash_table_entry { + HASH_ENTRY_VALID = 1, + SKIP = 2, + HASH_ENTRY_RECEIVE_DISCARD = 4, + HASH_ENTRY_RECEIVE_DISCARD_BIT = 2 +}; + +static int pxa168_get_settings(struct net_device *dev, struct ethtool_cmd *cmd); +static int pxa168_set_settings(struct net_device *dev, struct ethtool_cmd *cmd); +static int pxa168_init_hw(struct pxa168_eth_private *pep); +static void eth_port_reset(struct net_device *dev); +static void eth_port_start(struct net_device *dev); +static int pxa168_eth_open(struct net_device *dev); +static int pxa168_eth_stop(struct net_device *dev); +static int ethernet_phy_setup(struct net_device *dev); + +static inline u32 rdl(struct pxa168_eth_private *pep, int offset) +{ + return readl(pep->base + offset); +} + +static inline void wrl(struct pxa168_eth_private *pep, int offset, u32 data) +{ + writel(data, pep->base + offset); +} + +static void abort_dma(struct pxa168_eth_private *pep) +{ + int delay; + int max_retries = 40; + + do { + wrl(pep, SDMA_CMD, SDMA_CMD_AR | SDMA_CMD_AT); + udelay(100); + + delay = 10; + while ((rdl(pep, SDMA_CMD) & (SDMA_CMD_AR | SDMA_CMD_AT)) + && delay-- > 0) { + udelay(10); + } + } while (max_retries-- > 0 && delay <= 0); + + if (max_retries <= 0) + printk(KERN_ERR "%s : DMA Stuck\n", __func__); +} + +static int ethernet_phy_get(struct pxa168_eth_private *pep) +{ + unsigned int reg_data; + + reg_data = rdl(pep, PHY_ADDRESS); + + return (reg_data >> (5 * pep->port_num)) & 0x1f; +} + +static void ethernet_phy_set_addr(struct pxa168_eth_private *pep, int phy_addr) +{ + u32 reg_data; + int addr_shift = 5 * pep->port_num; + + reg_data = rdl(pep, PHY_ADDRESS); + reg_data &= ~(0x1f << addr_shift); + reg_data |= (phy_addr & 0x1f) << addr_shift; + wrl(pep, PHY_ADDRESS, reg_data); +} + +static void ethernet_phy_reset(struct pxa168_eth_private *pep) +{ + int data; + + data = phy_read(pep->phy, MII_BMCR); + if (data < 0) + return; + + data |= BMCR_RESET; + if (phy_write(pep->phy, MII_BMCR, data) < 0) + return; + + do { + data = phy_read(pep->phy, MII_BMCR); + } while (data >= 0 && data & BMCR_RESET); +} + +static void rxq_refill(struct net_device *dev) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + struct sk_buff *skb; + struct rx_desc *p_used_rx_desc; + int used_rx_desc; + + while (pep->rx_desc_count < pep->rx_ring_size) { + int size; + + skb = dev_alloc_skb(pep->skb_size); + if (!skb) + break; + if (SKB_DMA_REALIGN) + skb_reserve(skb, SKB_DMA_REALIGN); + pep->rx_desc_count++; + /* Get 'used' Rx descriptor */ + used_rx_desc = pep->rx_used_desc_q; + p_used_rx_desc = &pep->p_rx_desc_area[used_rx_desc]; + size = skb->end - skb->data; + p_used_rx_desc->buf_ptr = dma_map_single(NULL, + skb->data, + size, + DMA_FROM_DEVICE); + p_used_rx_desc->buf_size = size; + pep->rx_skb[used_rx_desc] = skb; + + /* Return the descriptor to DMA ownership */ + wmb(); + p_used_rx_desc->cmd_sts = BUF_OWNED_BY_DMA | RX_EN_INT; + wmb(); + + /* Move the used descriptor pointer to the next descriptor */ + pep->rx_used_desc_q = (used_rx_desc + 1) % pep->rx_ring_size; + + /* Any Rx return cancels the Rx resource error status */ + pep->rx_resource_err = 0; + + skb_reserve(skb, ETH_HW_IP_ALIGN); + } + + /* + * If RX ring is empty of SKB, set a timer to try allocating + * again at a later time. + */ + if (pep->rx_desc_count == 0) { + pep->timeout.expires = jiffies + (HZ / 10); + add_timer(&pep->timeout); + } +} + +static inline void rxq_refill_timer_wrapper(unsigned long data) +{ + struct pxa168_eth_private *pep = (void *)data; + napi_schedule(&pep->napi); +} + +static inline u8 flip_8_bits(u8 x) +{ + return (((x) & 0x01) << 3) | (((x) & 0x02) << 1) + | (((x) & 0x04) >> 1) | (((x) & 0x08) >> 3) + | (((x) & 0x10) << 3) | (((x) & 0x20) << 1) + | (((x) & 0x40) >> 1) | (((x) & 0x80) >> 3); +} + +static void nibble_swap_every_byte(unsigned char *mac_addr) +{ + int i; + for (i = 0; i < ETH_ALEN; i++) { + mac_addr[i] = ((mac_addr[i] & 0x0f) << 4) | + ((mac_addr[i] & 0xf0) >> 4); + } +} + +static void inverse_every_nibble(unsigned char *mac_addr) +{ + int i; + for (i = 0; i < ETH_ALEN; i++) + mac_addr[i] = flip_8_bits(mac_addr[i]); +} + +/* + * ---------------------------------------------------------------------------- + * This function will calculate the hash function of the address. + * Inputs + * mac_addr_orig - MAC address. + * Outputs + * return the calculated entry. + */ +static u32 hash_function(unsigned char *mac_addr_orig) +{ + u32 hash_result; + u32 addr0; + u32 addr1; + u32 addr2; + u32 addr3; + unsigned char mac_addr[ETH_ALEN]; + + /* Make a copy of MAC address since we are going to performe bit + * operations on it + */ + memcpy(mac_addr, mac_addr_orig, ETH_ALEN); + + nibble_swap_every_byte(mac_addr); + inverse_every_nibble(mac_addr); + + addr0 = (mac_addr[5] >> 2) & 0x3f; + addr1 = (mac_addr[5] & 0x03) | (((mac_addr[4] & 0x7f)) << 2); + addr2 = ((mac_addr[4] & 0x80) >> 7) | mac_addr[3] << 1; + addr3 = (mac_addr[2] & 0xff) | ((mac_addr[1] & 1) << 8); + + hash_result = (addr0 << 9) | (addr1 ^ addr2 ^ addr3); + hash_result = hash_result & 0x07ff; + return hash_result; +} + +/* + * ---------------------------------------------------------------------------- + * This function will add/del an entry to the address table. + * Inputs + * pep - ETHERNET . + * mac_addr - MAC address. + * skip - if 1, skip this address.Used in case of deleting an entry which is a + * part of chain in the hash table.We cant just delete the entry since + * that will break the chain.We need to defragment the tables time to + * time. + * rd - 0 Discard packet upon match. + * - 1 Receive packet upon match. + * Outputs + * address table entry is added/deleted. + * 0 if success. + * -ENOSPC if table full + */ +static int add_del_hash_entry(struct pxa168_eth_private *pep, + unsigned char *mac_addr, + u32 rd, u32 skip, int del) +{ + struct addr_table_entry *entry, *start; + u32 new_high; + u32 new_low; + u32 i; + + new_low = (((mac_addr[1] >> 4) & 0xf) << 15) + | (((mac_addr[1] >> 0) & 0xf) << 11) + | (((mac_addr[0] >> 4) & 0xf) << 7) + | (((mac_addr[0] >> 0) & 0xf) << 3) + | (((mac_addr[3] >> 4) & 0x1) << 31) + | (((mac_addr[3] >> 0) & 0xf) << 27) + | (((mac_addr[2] >> 4) & 0xf) << 23) + | (((mac_addr[2] >> 0) & 0xf) << 19) + | (skip << SKIP) | (rd << HASH_ENTRY_RECEIVE_DISCARD_BIT) + | HASH_ENTRY_VALID; + + new_high = (((mac_addr[5] >> 4) & 0xf) << 15) + | (((mac_addr[5] >> 0) & 0xf) << 11) + | (((mac_addr[4] >> 4) & 0xf) << 7) + | (((mac_addr[4] >> 0) & 0xf) << 3) + | (((mac_addr[3] >> 5) & 0x7) << 0); + + /* + * Pick the appropriate table, start scanning for free/reusable + * entries at the index obtained by hashing the specified MAC address + */ + start = (struct addr_table_entry *)(pep->htpr); + entry = start + hash_function(mac_addr); + for (i = 0; i < HOP_NUMBER; i++) { + if (!(le32_to_cpu(entry->lo) & HASH_ENTRY_VALID)) { + break; + } else { + /* if same address put in same position */ + if (((le32_to_cpu(entry->lo) & 0xfffffff8) == + (new_low & 0xfffffff8)) && + (le32_to_cpu(entry->hi) == new_high)) { + break; + } + } + if (entry == start + 0x7ff) + entry = start; + else + entry++; + } + + if (((le32_to_cpu(entry->lo) & 0xfffffff8) != (new_low & 0xfffffff8)) && + (le32_to_cpu(entry->hi) != new_high) && del) + return 0; + + if (i == HOP_NUMBER) { + if (!del) { + printk(KERN_INFO "%s: table section is full, need to " + "move to 16kB implementation?\n", + __FILE__); + return -ENOSPC; + } else + return 0; + } + + /* + * Update the selected entry + */ + if (del) { + entry->hi = 0; + entry->lo = 0; + } else { + entry->hi = cpu_to_le32(new_high); + entry->lo = cpu_to_le32(new_low); + } + + return 0; +} + +/* + * ---------------------------------------------------------------------------- + * Create an addressTable entry from MAC address info + * found in the specifed net_device struct + * + * Input : pointer to ethernet interface network device structure + * Output : N/A + */ +static void update_hash_table_mac_address(struct pxa168_eth_private *pep, + unsigned char *oaddr, + unsigned char *addr) +{ + /* Delete old entry */ + if (oaddr) + add_del_hash_entry(pep, oaddr, 1, 0, HASH_DELETE); + /* Add new entry */ + add_del_hash_entry(pep, addr, 1, 0, HASH_ADD); +} + +static int init_hash_table(struct pxa168_eth_private *pep) +{ + /* + * Hardware expects CPU to build a hash table based on a predefined + * hash function and populate it based on hardware address. The + * location of the hash table is identified by 32-bit pointer stored + * in HTPR internal register. Two possible sizes exists for the hash + * table 8kB (256kB of DRAM required (4 x 64 kB banks)) and 1/2kB + * (16kB of DRAM required (4 x 4 kB banks)).We currently only support + * 1/2kB. + */ + /* TODO: Add support for 8kB hash table and alternative hash + * function.Driver can dynamically switch to them if the 1/2kB hash + * table is full. + */ + if (pep->htpr == NULL) { + pep->htpr = dma_alloc_coherent(pep->dev->dev.parent, + HASH_ADDR_TABLE_SIZE, + &pep->htpr_dma, GFP_KERNEL); + if (pep->htpr == NULL) + return -ENOMEM; + } + memset(pep->htpr, 0, HASH_ADDR_TABLE_SIZE); + wrl(pep, HTPR, pep->htpr_dma); + return 0; +} + +static void pxa168_eth_set_rx_mode(struct net_device *dev) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + struct netdev_hw_addr *ha; + u32 val; + + val = rdl(pep, PORT_CONFIG); + if (dev->flags & IFF_PROMISC) + val |= PCR_PM; + else + val &= ~PCR_PM; + wrl(pep, PORT_CONFIG, val); + + /* + * Remove the old list of MAC address and add dev->addr + * and multicast address. + */ + memset(pep->htpr, 0, HASH_ADDR_TABLE_SIZE); + update_hash_table_mac_address(pep, NULL, dev->dev_addr); + + netdev_for_each_mc_addr(ha, dev) + update_hash_table_mac_address(pep, NULL, ha->addr); +} + +static int pxa168_eth_set_mac_address(struct net_device *dev, void *addr) +{ + struct sockaddr *sa = addr; + struct pxa168_eth_private *pep = netdev_priv(dev); + unsigned char oldMac[ETH_ALEN]; + + if (!is_valid_ether_addr(sa->sa_data)) + return -EINVAL; + memcpy(oldMac, dev->dev_addr, ETH_ALEN); + memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN); + netif_addr_lock_bh(dev); + update_hash_table_mac_address(pep, oldMac, dev->dev_addr); + netif_addr_unlock_bh(dev); + return 0; +} + +static void eth_port_start(struct net_device *dev) +{ + unsigned int val = 0; + struct pxa168_eth_private *pep = netdev_priv(dev); + int tx_curr_desc, rx_curr_desc; + + /* Perform PHY reset, if there is a PHY. */ + if (pep->phy != NULL) { + struct ethtool_cmd cmd; + + pxa168_get_settings(pep->dev, &cmd); + ethernet_phy_reset(pep); + pxa168_set_settings(pep->dev, &cmd); + } + + /* Assignment of Tx CTRP of given queue */ + tx_curr_desc = pep->tx_curr_desc_q; + wrl(pep, ETH_C_TX_DESC_1, + (u32) ((struct tx_desc *)pep->tx_desc_dma + tx_curr_desc)); + + /* Assignment of Rx CRDP of given queue */ + rx_curr_desc = pep->rx_curr_desc_q; + wrl(pep, ETH_C_RX_DESC_0, + (u32) ((struct rx_desc *)pep->rx_desc_dma + rx_curr_desc)); + + wrl(pep, ETH_F_RX_DESC_0, + (u32) ((struct rx_desc *)pep->rx_desc_dma + rx_curr_desc)); + + /* Clear all interrupts */ + wrl(pep, INT_CAUSE, 0); + + /* Enable all interrupts for receive, transmit and error. */ + wrl(pep, INT_MASK, ALL_INTS); + + val = rdl(pep, PORT_CONFIG); + val |= PCR_EN; + wrl(pep, PORT_CONFIG, val); + + /* Start RX DMA engine */ + val = rdl(pep, SDMA_CMD); + val |= SDMA_CMD_ERD; + wrl(pep, SDMA_CMD, val); +} + +static void eth_port_reset(struct net_device *dev) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + unsigned int val = 0; + + /* Stop all interrupts for receive, transmit and error. */ + wrl(pep, INT_MASK, 0); + + /* Clear all interrupts */ + wrl(pep, INT_CAUSE, 0); + + /* Stop RX DMA */ + val = rdl(pep, SDMA_CMD); + val &= ~SDMA_CMD_ERD; /* abort dma command */ + + /* Abort any transmit and receive operations and put DMA + * in idle state. + */ + abort_dma(pep); + + /* Disable port */ + val = rdl(pep, PORT_CONFIG); + val &= ~PCR_EN; + wrl(pep, PORT_CONFIG, val); +} + +/* + * txq_reclaim - Free the tx desc data for completed descriptors + * If force is non-zero, frees uncompleted descriptors as well + */ +static int txq_reclaim(struct net_device *dev, int force) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + struct tx_desc *desc; + u32 cmd_sts; + struct sk_buff *skb; + int tx_index; + dma_addr_t addr; + int count; + int released = 0; + + netif_tx_lock(dev); + + pep->work_todo &= ~WORK_TX_DONE; + while (pep->tx_desc_count > 0) { + tx_index = pep->tx_used_desc_q; + desc = &pep->p_tx_desc_area[tx_index]; + cmd_sts = desc->cmd_sts; + if (!force && (cmd_sts & BUF_OWNED_BY_DMA)) { + if (released > 0) { + goto txq_reclaim_end; + } else { + released = -1; + goto txq_reclaim_end; + } + } + pep->tx_used_desc_q = (tx_index + 1) % pep->tx_ring_size; + pep->tx_desc_count--; + addr = desc->buf_ptr; + count = desc->byte_cnt; + skb = pep->tx_skb[tx_index]; + if (skb) + pep->tx_skb[tx_index] = NULL; + + if (cmd_sts & TX_ERROR) { + if (net_ratelimit()) + printk(KERN_ERR "%s: Error in TX\n", dev->name); + dev->stats.tx_errors++; + } + dma_unmap_single(NULL, addr, count, DMA_TO_DEVICE); + if (skb) + dev_kfree_skb_irq(skb); + released++; + } +txq_reclaim_end: + netif_tx_unlock(dev); + return released; +} + +static void pxa168_eth_tx_timeout(struct net_device *dev) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + + printk(KERN_INFO "%s: TX timeout desc_count %d\n", + dev->name, pep->tx_desc_count); + + schedule_work(&pep->tx_timeout_task); +} + +static void pxa168_eth_tx_timeout_task(struct work_struct *work) +{ + struct pxa168_eth_private *pep = container_of(work, + struct pxa168_eth_private, + tx_timeout_task); + struct net_device *dev = pep->dev; + pxa168_eth_stop(dev); + pxa168_eth_open(dev); +} + +static int rxq_process(struct net_device *dev, int budget) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + unsigned int received_packets = 0; + struct sk_buff *skb; + + while (budget-- > 0) { + int rx_next_curr_desc, rx_curr_desc, rx_used_desc; + struct rx_desc *rx_desc; + unsigned int cmd_sts; + + /* Do not process Rx ring in case of Rx ring resource error */ + if (pep->rx_resource_err) + break; + rx_curr_desc = pep->rx_curr_desc_q; + rx_used_desc = pep->rx_used_desc_q; + rx_desc = &pep->p_rx_desc_area[rx_curr_desc]; + cmd_sts = rx_desc->cmd_sts; + rmb(); + if (cmd_sts & (BUF_OWNED_BY_DMA)) + break; + skb = pep->rx_skb[rx_curr_desc]; + pep->rx_skb[rx_curr_desc] = NULL; + + rx_next_curr_desc = (rx_curr_desc + 1) % pep->rx_ring_size; + pep->rx_curr_desc_q = rx_next_curr_desc; + + /* Rx descriptors exhausted. */ + /* Set the Rx ring resource error flag */ + if (rx_next_curr_desc == rx_used_desc) + pep->rx_resource_err = 1; + pep->rx_desc_count--; + dma_unmap_single(NULL, rx_desc->buf_ptr, + rx_desc->buf_size, + DMA_FROM_DEVICE); + received_packets++; + /* + * Update statistics. + * Note byte count includes 4 byte CRC count + */ + stats->rx_packets++; + stats->rx_bytes += rx_desc->byte_cnt; + /* + * In case received a packet without first / last bits on OR + * the error summary bit is on, the packets needs to be droped. + */ + if (((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC)) != + (RX_FIRST_DESC | RX_LAST_DESC)) + || (cmd_sts & RX_ERROR)) { + + stats->rx_dropped++; + if ((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC)) != + (RX_FIRST_DESC | RX_LAST_DESC)) { + if (net_ratelimit()) + printk(KERN_ERR + "%s: Rx pkt on multiple desc\n", + dev->name); + } + if (cmd_sts & RX_ERROR) + stats->rx_errors++; + dev_kfree_skb_irq(skb); + } else { + /* + * The -4 is for the CRC in the trailer of the + * received packet + */ + skb_put(skb, rx_desc->byte_cnt - 4); + skb->protocol = eth_type_trans(skb, dev); + netif_receive_skb(skb); + } + dev->last_rx = jiffies; + } + /* Fill RX ring with skb's */ + rxq_refill(dev); + return received_packets; +} + +static int pxa168_eth_collect_events(struct pxa168_eth_private *pep, + struct net_device *dev) +{ + u32 icr; + int ret = 0; + + icr = rdl(pep, INT_CAUSE); + if (icr == 0) + return IRQ_NONE; + + wrl(pep, INT_CAUSE, ~icr); + if (icr & (ICR_TXBUF_H | ICR_TXBUF_L)) { + pep->work_todo |= WORK_TX_DONE; + ret = 1; + } + if (icr & ICR_RXBUF) + ret = 1; + if (icr & ICR_MII_CH) { + pep->work_todo |= WORK_LINK; + ret = 1; + } + return ret; +} + +static void handle_link_event(struct pxa168_eth_private *pep) +{ + struct net_device *dev = pep->dev; + u32 port_status; + int speed; + int duplex; + int fc; + + port_status = rdl(pep, PORT_STATUS); + if (!(port_status & LINK_UP)) { + if (netif_carrier_ok(dev)) { + printk(KERN_INFO "%s: link down\n", dev->name); + netif_carrier_off(dev); + txq_reclaim(dev, 1); + } + return; + } + if (port_status & PORT_SPEED_100) + speed = 100; + else + speed = 10; + + duplex = (port_status & FULL_DUPLEX) ? 1 : 0; + fc = (port_status & FLOW_CONTROL_ENABLED) ? 1 : 0; + printk(KERN_INFO "%s: link up, %d Mb/s, %s duplex, " + "flow control %sabled\n", dev->name, + speed, duplex ? "full" : "half", fc ? "en" : "dis"); + if (!netif_carrier_ok(dev)) + netif_carrier_on(dev); +} + +static irqreturn_t pxa168_eth_int_handler(int irq, void *dev_id) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct pxa168_eth_private *pep = netdev_priv(dev); + + if (unlikely(!pxa168_eth_collect_events(pep, dev))) + return IRQ_NONE; + /* Disable interrupts */ + wrl(pep, INT_MASK, 0); + napi_schedule(&pep->napi); + return IRQ_HANDLED; +} + +static void pxa168_eth_recalc_skb_size(struct pxa168_eth_private *pep) +{ + int skb_size; + + /* + * Reserve 2+14 bytes for an ethernet header (the hardware + * automatically prepends 2 bytes of dummy data to each + * received packet), 16 bytes for up to four VLAN tags, and + * 4 bytes for the trailing FCS -- 36 bytes total. + */ + skb_size = pep->dev->mtu + 36; + + /* + * Make sure that the skb size is a multiple of 8 bytes, as + * the lower three bits of the receive descriptor's buffer + * size field are ignored by the hardware. + */ + pep->skb_size = (skb_size + 7) & ~7; + + /* + * If NET_SKB_PAD is smaller than a cache line, + * netdev_alloc_skb() will cause skb->data to be misaligned + * to a cache line boundary. If this is the case, include + * some extra space to allow re-aligning the data area. + */ + pep->skb_size += SKB_DMA_REALIGN; + +} + +static int set_port_config_ext(struct pxa168_eth_private *pep) +{ + int skb_size; + + pxa168_eth_recalc_skb_size(pep); + if (pep->skb_size <= 1518) + skb_size = PCXR_MFL_1518; + else if (pep->skb_size <= 1536) + skb_size = PCXR_MFL_1536; + else if (pep->skb_size <= 2048) + skb_size = PCXR_MFL_2048; + else + skb_size = PCXR_MFL_64K; + + /* Extended Port Configuration */ + wrl(pep, + PORT_CONFIG_EXT, PCXR_2BSM | /* Two byte prefix aligns IP hdr */ + PCXR_DSCP_EN | /* Enable DSCP in IP */ + skb_size | PCXR_FLP | /* do not force link pass */ + PCXR_TX_HIGH_PRI); /* Transmit - high priority queue */ + + return 0; +} + +static int pxa168_init_hw(struct pxa168_eth_private *pep) +{ + int err = 0; + + /* Disable interrupts */ + wrl(pep, INT_MASK, 0); + wrl(pep, INT_CAUSE, 0); + /* Write to ICR to clear interrupts. */ + wrl(pep, INT_W_CLEAR, 0); + /* Abort any transmit and receive operations and put DMA + * in idle state. + */ + abort_dma(pep); + /* Initialize address hash table */ + err = init_hash_table(pep); + if (err) + return err; + /* SDMA configuration */ + wrl(pep, SDMA_CONFIG, SDCR_BSZ8 | /* Burst size = 32 bytes */ + SDCR_RIFB | /* Rx interrupt on frame */ + SDCR_BLMT | /* Little endian transmit */ + SDCR_BLMR | /* Little endian receive */ + SDCR_RC_MAX_RETRANS); /* Max retransmit count */ + /* Port Configuration */ + wrl(pep, PORT_CONFIG, PCR_HS); /* Hash size is 1/2kb */ + set_port_config_ext(pep); + + return err; +} + +static int rxq_init(struct net_device *dev) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + struct rx_desc *p_rx_desc; + int size = 0, i = 0; + int rx_desc_num = pep->rx_ring_size; + + /* Allocate RX skb rings */ + pep->rx_skb = kmalloc(sizeof(*pep->rx_skb) * pep->rx_ring_size, + GFP_KERNEL); + if (!pep->rx_skb) { + printk(KERN_ERR "%s: Cannot alloc RX skb ring\n", dev->name); + return -ENOMEM; + } + /* Allocate RX ring */ + pep->rx_desc_count = 0; + size = pep->rx_ring_size * sizeof(struct rx_desc); + pep->rx_desc_area_size = size; + pep->p_rx_desc_area = dma_alloc_coherent(pep->dev->dev.parent, size, + &pep->rx_desc_dma, GFP_KERNEL); + if (!pep->p_rx_desc_area) { + printk(KERN_ERR "%s: Cannot alloc RX ring (size %d bytes)\n", + dev->name, size); + goto out; + } + memset((void *)pep->p_rx_desc_area, 0, size); + /* initialize the next_desc_ptr links in the Rx descriptors ring */ + p_rx_desc = (struct rx_desc *)pep->p_rx_desc_area; + for (i = 0; i < rx_desc_num; i++) { + p_rx_desc[i].next_desc_ptr = pep->rx_desc_dma + + ((i + 1) % rx_desc_num) * sizeof(struct rx_desc); + } + /* Save Rx desc pointer to driver struct. */ + pep->rx_curr_desc_q = 0; + pep->rx_used_desc_q = 0; + pep->rx_desc_area_size = rx_desc_num * sizeof(struct rx_desc); + return 0; +out: + kfree(pep->rx_skb); + return -ENOMEM; +} + +static void rxq_deinit(struct net_device *dev) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + int curr; + + /* Free preallocated skb's on RX rings */ + for (curr = 0; pep->rx_desc_count && curr < pep->rx_ring_size; curr++) { + if (pep->rx_skb[curr]) { + dev_kfree_skb(pep->rx_skb[curr]); + pep->rx_desc_count--; + } + } + if (pep->rx_desc_count) + printk(KERN_ERR + "Error in freeing Rx Ring. %d skb's still\n", + pep->rx_desc_count); + /* Free RX ring */ + if (pep->p_rx_desc_area) + dma_free_coherent(pep->dev->dev.parent, pep->rx_desc_area_size, + pep->p_rx_desc_area, pep->rx_desc_dma); + kfree(pep->rx_skb); +} + +static int txq_init(struct net_device *dev) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + struct tx_desc *p_tx_desc; + int size = 0, i = 0; + int tx_desc_num = pep->tx_ring_size; + + pep->tx_skb = kmalloc(sizeof(*pep->tx_skb) * pep->tx_ring_size, + GFP_KERNEL); + if (!pep->tx_skb) { + printk(KERN_ERR "%s: Cannot alloc TX skb ring\n", dev->name); + return -ENOMEM; + } + /* Allocate TX ring */ + pep->tx_desc_count = 0; + size = pep->tx_ring_size * sizeof(struct tx_desc); + pep->tx_desc_area_size = size; + pep->p_tx_desc_area = dma_alloc_coherent(pep->dev->dev.parent, size, + &pep->tx_desc_dma, GFP_KERNEL); + if (!pep->p_tx_desc_area) { + printk(KERN_ERR "%s: Cannot allocate Tx Ring (size %d bytes)\n", + dev->name, size); + goto out; + } + memset((void *)pep->p_tx_desc_area, 0, pep->tx_desc_area_size); + /* Initialize the next_desc_ptr links in the Tx descriptors ring */ + p_tx_desc = (struct tx_desc *)pep->p_tx_desc_area; + for (i = 0; i < tx_desc_num; i++) { + p_tx_desc[i].next_desc_ptr = pep->tx_desc_dma + + ((i + 1) % tx_desc_num) * sizeof(struct tx_desc); + } + pep->tx_curr_desc_q = 0; + pep->tx_used_desc_q = 0; + pep->tx_desc_area_size = tx_desc_num * sizeof(struct tx_desc); + return 0; +out: + kfree(pep->tx_skb); + return -ENOMEM; +} + +static void txq_deinit(struct net_device *dev) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + + /* Free outstanding skb's on TX ring */ + txq_reclaim(dev, 1); + BUG_ON(pep->tx_used_desc_q != pep->tx_curr_desc_q); + /* Free TX ring */ + if (pep->p_tx_desc_area) + dma_free_coherent(pep->dev->dev.parent, pep->tx_desc_area_size, + pep->p_tx_desc_area, pep->tx_desc_dma); + kfree(pep->tx_skb); +} + +static int pxa168_eth_open(struct net_device *dev) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + int err; + + err = request_irq(dev->irq, pxa168_eth_int_handler, + IRQF_DISABLED, dev->name, dev); + if (err) { + dev_printk(KERN_ERR, &dev->dev, "can't assign irq\n"); + return -EAGAIN; + } + pep->rx_resource_err = 0; + err = rxq_init(dev); + if (err != 0) + goto out_free_irq; + err = txq_init(dev); + if (err != 0) + goto out_free_rx_skb; + pep->rx_used_desc_q = 0; + pep->rx_curr_desc_q = 0; + + /* Fill RX ring with skb's */ + rxq_refill(dev); + pep->rx_used_desc_q = 0; + pep->rx_curr_desc_q = 0; + netif_carrier_off(dev); + eth_port_start(dev); + napi_enable(&pep->napi); + return 0; +out_free_rx_skb: + rxq_deinit(dev); +out_free_irq: + free_irq(dev->irq, dev); + return err; +} + +static int pxa168_eth_stop(struct net_device *dev) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + eth_port_reset(dev); + + /* Disable interrupts */ + wrl(pep, INT_MASK, 0); + wrl(pep, INT_CAUSE, 0); + /* Write to ICR to clear interrupts. */ + wrl(pep, INT_W_CLEAR, 0); + napi_disable(&pep->napi); + del_timer_sync(&pep->timeout); + netif_carrier_off(dev); + free_irq(dev->irq, dev); + rxq_deinit(dev); + txq_deinit(dev); + + return 0; +} + +static int pxa168_eth_change_mtu(struct net_device *dev, int mtu) +{ + int retval; + struct pxa168_eth_private *pep = netdev_priv(dev); + + if ((mtu > 9500) || (mtu < 68)) + return -EINVAL; + + dev->mtu = mtu; + retval = set_port_config_ext(pep); + + if (!netif_running(dev)) + return 0; + + /* + * Stop and then re-open the interface. This will allocate RX + * skbs of the new MTU. + * There is a possible danger that the open will not succeed, + * due to memory being full. + */ + pxa168_eth_stop(dev); + if (pxa168_eth_open(dev)) { + dev_printk(KERN_ERR, &dev->dev, + "fatal error on re-opening device after " + "MTU change\n"); + } + + return 0; +} + +static int eth_alloc_tx_desc_index(struct pxa168_eth_private *pep) +{ + int tx_desc_curr; + + tx_desc_curr = pep->tx_curr_desc_q; + pep->tx_curr_desc_q = (tx_desc_curr + 1) % pep->tx_ring_size; + BUG_ON(pep->tx_curr_desc_q == pep->tx_used_desc_q); + pep->tx_desc_count++; + + return tx_desc_curr; +} + +static int pxa168_rx_poll(struct napi_struct *napi, int budget) +{ + struct pxa168_eth_private *pep = + container_of(napi, struct pxa168_eth_private, napi); + struct net_device *dev = pep->dev; + int work_done = 0; + + if (unlikely(pep->work_todo & WORK_LINK)) { + pep->work_todo &= ~(WORK_LINK); + handle_link_event(pep); + } + /* + * We call txq_reclaim every time since in NAPI interupts are disabled + * and due to this we miss the TX_DONE interrupt,which is not updated in + * interrupt status register. + */ + txq_reclaim(dev, 0); + if (netif_queue_stopped(dev) + && pep->tx_ring_size - pep->tx_desc_count > 1) { + netif_wake_queue(dev); + } + work_done = rxq_process(dev, budget); + if (work_done < budget) { + napi_complete(napi); + wrl(pep, INT_MASK, ALL_INTS); + } + + return work_done; +} + +static int pxa168_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + struct tx_desc *desc; + int tx_index; + int length; + + tx_index = eth_alloc_tx_desc_index(pep); + desc = &pep->p_tx_desc_area[tx_index]; + length = skb->len; + pep->tx_skb[tx_index] = skb; + desc->byte_cnt = length; + desc->buf_ptr = dma_map_single(NULL, skb->data, length, DMA_TO_DEVICE); + wmb(); + desc->cmd_sts = BUF_OWNED_BY_DMA | TX_GEN_CRC | TX_FIRST_DESC | + TX_ZERO_PADDING | TX_LAST_DESC | TX_EN_INT; + wmb(); + wrl(pep, SDMA_CMD, SDMA_CMD_TXDH | SDMA_CMD_ERD); + + stats->tx_bytes += skb->len; + stats->tx_packets++; + dev->trans_start = jiffies; + if (pep->tx_ring_size - pep->tx_desc_count <= 1) { + /* We handled the current skb, but now we are out of space.*/ + netif_stop_queue(dev); + } + + return NETDEV_TX_OK; +} + +static int smi_wait_ready(struct pxa168_eth_private *pep) +{ + int i = 0; + + /* wait for the SMI register to become available */ + for (i = 0; rdl(pep, SMI) & SMI_BUSY; i++) { + if (i == PHY_WAIT_ITERATIONS) + return -ETIMEDOUT; + msleep(10); + } + + return 0; +} + +static int pxa168_smi_read(struct mii_bus *bus, int phy_addr, int regnum) +{ + struct pxa168_eth_private *pep = bus->priv; + int i = 0; + int val; + + if (smi_wait_ready(pep)) { + printk(KERN_WARNING "pxa168_eth: SMI bus busy timeout\n"); + return -ETIMEDOUT; + } + wrl(pep, SMI, (phy_addr << 16) | (regnum << 21) | SMI_OP_R); + /* now wait for the data to be valid */ + for (i = 0; !((val = rdl(pep, SMI)) & SMI_R_VALID); i++) { + if (i == PHY_WAIT_ITERATIONS) { + printk(KERN_WARNING + "pxa168_eth: SMI bus read not valid\n"); + return -ENODEV; + } + msleep(10); + } + + return val & 0xffff; +} + +static int pxa168_smi_write(struct mii_bus *bus, int phy_addr, int regnum, + u16 value) +{ + struct pxa168_eth_private *pep = bus->priv; + + if (smi_wait_ready(pep)) { + printk(KERN_WARNING "pxa168_eth: SMI bus busy timeout\n"); + return -ETIMEDOUT; + } + + wrl(pep, SMI, (phy_addr << 16) | (regnum << 21) | + SMI_OP_W | (value & 0xffff)); + + if (smi_wait_ready(pep)) { + printk(KERN_ERR "pxa168_eth: SMI bus busy timeout\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int pxa168_eth_do_ioctl(struct net_device *dev, struct ifreq *ifr, + int cmd) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + if (pep->phy != NULL) + return phy_mii_ioctl(pep->phy, if_mii(ifr), cmd); + + return -EOPNOTSUPP; +} + +static struct phy_device *phy_scan(struct pxa168_eth_private *pep, int phy_addr) +{ + struct mii_bus *bus = pep->smi_bus; + struct phy_device *phydev; + int start; + int num; + int i; + + if (phy_addr == PXA168_ETH_PHY_ADDR_DEFAULT) { + /* Scan entire range */ + start = ethernet_phy_get(pep); + num = 32; + } else { + /* Use phy addr specific to platform */ + start = phy_addr & 0x1f; + num = 1; + } + phydev = NULL; + for (i = 0; i < num; i++) { + int addr = (start + i) & 0x1f; + if (bus->phy_map[addr] == NULL) + mdiobus_scan(bus, addr); + + if (phydev == NULL) { + phydev = bus->phy_map[addr]; + if (phydev != NULL) + ethernet_phy_set_addr(pep, addr); + } + } + + return phydev; +} + +static void phy_init(struct pxa168_eth_private *pep, int speed, int duplex) +{ + struct phy_device *phy = pep->phy; + ethernet_phy_reset(pep); + + phy_attach(pep->dev, dev_name(&phy->dev), 0, PHY_INTERFACE_MODE_MII); + + if (speed == 0) { + phy->autoneg = AUTONEG_ENABLE; + phy->speed = 0; + phy->duplex = 0; + phy->supported &= PHY_BASIC_FEATURES; + phy->advertising = phy->supported | ADVERTISED_Autoneg; + } else { + phy->autoneg = AUTONEG_DISABLE; + phy->advertising = 0; + phy->speed = speed; + phy->duplex = duplex; + } + phy_start_aneg(phy); +} + +static int ethernet_phy_setup(struct net_device *dev) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + + if (pep->pd != NULL) { + if (pep->pd->init) + pep->pd->init(); + } + pep->phy = phy_scan(pep, pep->pd->phy_addr & 0x1f); + if (pep->phy != NULL) + phy_init(pep, pep->pd->speed, pep->pd->duplex); + update_hash_table_mac_address(pep, NULL, dev->dev_addr); + + return 0; +} + +static int pxa168_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + int err; + + err = phy_read_status(pep->phy); + if (err == 0) + err = phy_ethtool_gset(pep->phy, cmd); + + return err; +} + +static int pxa168_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + + return phy_ethtool_sset(pep->phy, cmd); +} + +static void pxa168_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + strncpy(info->driver, DRIVER_NAME, 32); + strncpy(info->version, DRIVER_VERSION, 32); + strncpy(info->fw_version, "N/A", 32); + strncpy(info->bus_info, "N/A", 32); +} + +static u32 pxa168_get_link(struct net_device *dev) +{ + return !!netif_carrier_ok(dev); +} + +static const struct ethtool_ops pxa168_ethtool_ops = { + .get_settings = pxa168_get_settings, + .set_settings = pxa168_set_settings, + .get_drvinfo = pxa168_get_drvinfo, + .get_link = pxa168_get_link, +}; + +static const struct net_device_ops pxa168_eth_netdev_ops = { + .ndo_open = pxa168_eth_open, + .ndo_stop = pxa168_eth_stop, + .ndo_start_xmit = pxa168_eth_start_xmit, + .ndo_set_rx_mode = pxa168_eth_set_rx_mode, + .ndo_set_mac_address = pxa168_eth_set_mac_address, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = pxa168_eth_do_ioctl, + .ndo_change_mtu = pxa168_eth_change_mtu, + .ndo_tx_timeout = pxa168_eth_tx_timeout, +}; + +static int pxa168_eth_probe(struct platform_device *pdev) +{ + struct pxa168_eth_private *pep = NULL; + struct net_device *dev = NULL; + struct resource *res; + struct clk *clk; + int err; + + printk(KERN_NOTICE "PXA168 10/100 Ethernet Driver\n"); + + clk = clk_get(&pdev->dev, "MFUCLK"); + if (IS_ERR(clk)) { + printk(KERN_ERR "%s: Fast Ethernet failed to get clock\n", + DRIVER_NAME); + return -ENODEV; + } + clk_enable(clk); + + dev = alloc_etherdev(sizeof(struct pxa168_eth_private)); + if (!dev) { + err = -ENOMEM; + goto out; + } + + platform_set_drvdata(pdev, dev); + pep = netdev_priv(dev); + pep->dev = dev; + pep->clk = clk; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + err = -ENODEV; + goto out; + } + pep->base = ioremap(res->start, res->end - res->start + 1); + if (pep->base == NULL) { + err = -ENOMEM; + goto out; + } + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + BUG_ON(!res); + dev->irq = res->start; + dev->netdev_ops = &pxa168_eth_netdev_ops; + dev->watchdog_timeo = 2 * HZ; + dev->base_addr = 0; + SET_ETHTOOL_OPS(dev, &pxa168_ethtool_ops); + + INIT_WORK(&pep->tx_timeout_task, pxa168_eth_tx_timeout_task); + + printk(KERN_INFO "%s:Using random mac address\n", DRIVER_NAME); + random_ether_addr(dev->dev_addr); + + pep->pd = pdev->dev.platform_data; + pep->rx_ring_size = NUM_RX_DESCS; + if (pep->pd->rx_queue_size) + pep->rx_ring_size = pep->pd->rx_queue_size; + + pep->tx_ring_size = NUM_TX_DESCS; + if (pep->pd->tx_queue_size) + pep->tx_ring_size = pep->pd->tx_queue_size; + + pep->port_num = pep->pd->port_number; + /* Hardware supports only 3 ports */ + BUG_ON(pep->port_num > 2); + netif_napi_add(dev, &pep->napi, pxa168_rx_poll, pep->rx_ring_size); + + memset(&pep->timeout, 0, sizeof(struct timer_list)); + init_timer(&pep->timeout); + pep->timeout.function = rxq_refill_timer_wrapper; + pep->timeout.data = (unsigned long)pep; + + pep->smi_bus = mdiobus_alloc(); + if (pep->smi_bus == NULL) { + err = -ENOMEM; + goto out; + } + pep->smi_bus->priv = pep; + pep->smi_bus->name = "pxa168_eth smi"; + pep->smi_bus->read = pxa168_smi_read; + pep->smi_bus->write = pxa168_smi_write; + snprintf(pep->smi_bus->id, MII_BUS_ID_SIZE, "%d", pdev->id); + pep->smi_bus->parent = &pdev->dev; + pep->smi_bus->phy_mask = 0xffffffff; + if (mdiobus_register(pep->smi_bus) < 0) { + err = -ENOMEM; + goto out; + } + pxa168_init_hw(pep); + err = ethernet_phy_setup(dev); + if (err) + goto out; + SET_NETDEV_DEV(dev, &pdev->dev); + err = register_netdev(dev); + if (err) + goto out; + return 0; +out: + if (pep->clk) { + clk_disable(pep->clk); + clk_put(pep->clk); + pep->clk = NULL; + } + if (pep->base) { + iounmap(pep->base); + pep->base = NULL; + } + if (dev) + free_netdev(dev); + return err; +} + +static int pxa168_eth_remove(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct pxa168_eth_private *pep = netdev_priv(dev); + + if (pep->htpr) { + dma_free_coherent(pep->dev->dev.parent, HASH_ADDR_TABLE_SIZE, + pep->htpr, pep->htpr_dma); + pep->htpr = NULL; + } + if (pep->clk) { + clk_disable(pep->clk); + clk_put(pep->clk); + pep->clk = NULL; + } + if (pep->phy != NULL) + phy_detach(pep->phy); + + iounmap(pep->base); + pep->base = NULL; + unregister_netdev(dev); + flush_scheduled_work(); + free_netdev(dev); + platform_set_drvdata(pdev, NULL); + return 0; +} + +static void pxa168_eth_shutdown(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + eth_port_reset(dev); +} + +#ifdef CONFIG_PM +static int pxa168_eth_resume(struct platform_device *pdev) +{ + return -ENOSYS; +} + +static int pxa168_eth_suspend(struct platform_device *pdev, pm_message_t state) +{ + return -ENOSYS; +} + +#else +#define pxa168_eth_resume NULL +#define pxa168_eth_suspend NULL +#endif + +static struct platform_driver pxa168_eth_driver = { + .probe = pxa168_eth_probe, + .remove = pxa168_eth_remove, + .shutdown = pxa168_eth_shutdown, + .resume = pxa168_eth_resume, + .suspend = pxa168_eth_suspend, + .driver = { + .name = DRIVER_NAME, + }, +}; + +static int __init pxa168_init_module(void) +{ + return platform_driver_register(&pxa168_eth_driver); +} + +static void __exit pxa168_cleanup_module(void) +{ + platform_driver_unregister(&pxa168_eth_driver); +} + +module_init(pxa168_init_module); +module_exit(pxa168_cleanup_module); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Ethernet driver for Marvell PXA168"); +MODULE_ALIAS("platform:pxa168_eth"); diff --git a/include/linux/pxa168_eth.h b/include/linux/pxa168_eth.h new file mode 100644 index 0000000..18d75e7 --- /dev/null +++ b/include/linux/pxa168_eth.h @@ -0,0 +1,30 @@ +/* + *pxa168 ethernet platform device data definition file. + */ +#ifndef __LINUX_PXA168_ETH_H +#define __LINUX_PXA168_ETH_H + +struct pxa168_eth_platform_data { + int port_number; + int phy_addr; + + /* + * If speed is 0, then speed and duplex are autonegotiated. + */ + int speed; /* 0, SPEED_10, SPEED_100 */ + int duplex; /* DUPLEX_HALF or DUPLEX_FULL */ + + /* + * Override default RX/TX queue sizes if nonzero. + */ + int rx_queue_size; + int tx_queue_size; + + /* + * init callback is used for board specific initialization + * e.g on Aspenite its used to initialize the PHY transceiver. + */ + int (*init)(void); +}; + +#endif /* __LINUX_PXA168_ETH_H */ -- cgit v0.10.2 From e243f5b6de35b6fc394bc2e1e1737afe538e7e0c Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sun, 15 Aug 2010 10:03:57 +0000 Subject: netfilter: fix userspace header warning "make headers_check" issued the following warning: CHECK include/linux/netfilter (64 files) usr/include/linux/netfilter/xt_ipvs.h:19: found __[us]{8,16,32,64} type without #include Fix this by as suggested including linux/types.h. Signed-off-by: Sam Ravnborg Signed-off-by: David S. Miller diff --git a/include/linux/netfilter/xt_ipvs.h b/include/linux/netfilter/xt_ipvs.h index 1167aeb..eff34ac 100644 --- a/include/linux/netfilter/xt_ipvs.h +++ b/include/linux/netfilter/xt_ipvs.h @@ -1,6 +1,8 @@ #ifndef _XT_IPVS_H #define _XT_IPVS_H +#include + enum { XT_IPVS_IPVS_PROPERTY = 1 << 0, /* all other options imply this one */ XT_IPVS_PROTO = 1 << 1, -- cgit v0.10.2 From 68d6ac6d2740b6a55f3ae92a4e0be6d881904b32 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 15 Aug 2010 21:20:44 +0000 Subject: netlink: fix compat recvmsg Since commit 1dacc76d0014a034b8aca14237c127d7c19d7726 Author: Johannes Berg Date: Wed Jul 1 11:26:02 2009 +0000 net/compat/wext: send different messages to compat tasks we had a race condition when setting and then restoring frag_list. Eric attempted to fix it, but the fix created even worse problems. However, the original motivation I had when I added the code that turned out to be racy is no longer clear to me, since we only copy up to skb->len to userspace, which doesn't include the frag_list length. As a result, not doing any frag_list clearing and restoring avoids the race condition, while not introducing any other problems. Additionally, while preparing this patch I found that since none of the remaining netlink code is really aware of the frag_list, we need to use the original skb's information for packet information and credentials. This fixes, for example, the group information received by compat tasks. Cc: Eric Dumazet Cc: stable@kernel.org [2.6.31+, for 2.6.35 revert 1235f504aa] Signed-off-by: Johannes Berg Acked-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 8648a99..980fe4a 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1406,7 +1406,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, struct netlink_sock *nlk = nlk_sk(sk); int noblock = flags&MSG_DONTWAIT; size_t copied; - struct sk_buff *skb, *frag __maybe_unused = NULL; + struct sk_buff *skb, *data_skb; int err; if (flags&MSG_OOB) @@ -1418,45 +1418,35 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, if (skb == NULL) goto out; + data_skb = skb; + #ifdef CONFIG_COMPAT_NETLINK_MESSAGES if (unlikely(skb_shinfo(skb)->frag_list)) { - bool need_compat = !!(flags & MSG_CMSG_COMPAT); - /* - * If this skb has a frag_list, then here that means that - * we will have to use the frag_list skb for compat tasks - * and the regular skb for non-compat tasks. + * If this skb has a frag_list, then here that means that we + * will have to use the frag_list skb's data for compat tasks + * and the regular skb's data for normal (non-compat) tasks. * - * The skb might (and likely will) be cloned, so we can't - * just reset frag_list and go on with things -- we need to - * keep that. For the compat case that's easy -- simply get - * a reference to the compat skb and free the regular one - * including the frag. For the non-compat case, we need to - * avoid sending the frag to the user -- so assign NULL but - * restore it below before freeing the skb. + * If we need to send the compat skb, assign it to the + * 'data_skb' variable so that it will be used below for data + * copying. We keep 'skb' for everything else, including + * freeing both later. */ - if (need_compat) { - struct sk_buff *compskb = skb_shinfo(skb)->frag_list; - skb_get(compskb); - kfree_skb(skb); - skb = compskb; - } else { - frag = skb_shinfo(skb)->frag_list; - skb_shinfo(skb)->frag_list = NULL; - } + if (flags & MSG_CMSG_COMPAT) + data_skb = skb_shinfo(skb)->frag_list; } #endif msg->msg_namelen = 0; - copied = skb->len; + copied = data_skb->len; if (len < copied) { msg->msg_flags |= MSG_TRUNC; copied = len; } - skb_reset_transport_header(skb); - err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + skb_reset_transport_header(data_skb); + err = skb_copy_datagram_iovec(data_skb, 0, msg->msg_iov, copied); if (msg->msg_name) { struct sockaddr_nl *addr = (struct sockaddr_nl *)msg->msg_name; @@ -1476,11 +1466,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, } siocb->scm->creds = *NETLINK_CREDS(skb); if (flags & MSG_TRUNC) - copied = skb->len; - -#ifdef CONFIG_COMPAT_NETLINK_MESSAGES - skb_shinfo(skb)->frag_list = frag; -#endif + copied = data_skb->len; skb_free_datagram(sk, skb); -- cgit v0.10.2 From f037590fff3005ce8a1513858d7d44f50053cc8f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 16 Aug 2010 03:25:00 +0000 Subject: rds: fix a leak of kernel memory struct rds_rdma_notify contains a 32 bits hole on 64bit arches, make sure it is zeroed before copying it to user. Signed-off-by: Eric Dumazet CC: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/recv.c b/net/rds/recv.c index 795a00b..c93588c 100644 --- a/net/rds/recv.c +++ b/net/rds/recv.c @@ -297,7 +297,7 @@ static int rds_still_queued(struct rds_sock *rs, struct rds_incoming *inc, int rds_notify_queue_get(struct rds_sock *rs, struct msghdr *msghdr) { struct rds_notifier *notifier; - struct rds_rdma_notify cmsg; + struct rds_rdma_notify cmsg = { 0 }; /* fill holes with zero */ unsigned int count = 0, max_messages = ~0U; unsigned long flags; LIST_HEAD(copy); -- cgit v0.10.2 From 3971a230f9573cca1cbef96dab05e2682820f1a0 Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Mon, 16 Aug 2010 06:34:06 +0000 Subject: bnx2x: Fix PHY locking problem PHY locking is required between two ports for some external PHYs. Since initialization was done in the common init function (called only on the first port initialization) rather than in the port init function, there was in fact no PHY locking between the ports. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index b4ec2b0..f8c3f08 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -4328,10 +4328,12 @@ static int bnx2x_init_port(struct bnx2x *bp) val |= aeu_gpio_mask; REG_WR(bp, offset, val); } + bp->port.need_hw_lock = 1; break; - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: + bp->port.need_hw_lock = 1; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: /* add SPIO 5 to group 0 */ { u32 reg_addr = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 : @@ -4341,7 +4343,10 @@ static int bnx2x_init_port(struct bnx2x *bp) REG_WR(bp, reg_addr, val); } break; - + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: + bp->port.need_hw_lock = 1; + break; default: break; } -- cgit v0.10.2 From 96ac4f6b326450af496e82347e207b0fca7a9090 Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Mon, 16 Aug 2010 06:34:07 +0000 Subject: bnx2x: Update bnx2x version to 1.52.53-4 Update bnx2x version to 1.52.53-4 Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x/bnx2x.h b/drivers/net/bnx2x/bnx2x.h index 53af9c9..0c2d96e 100644 --- a/drivers/net/bnx2x/bnx2x.h +++ b/drivers/net/bnx2x/bnx2x.h @@ -20,8 +20,8 @@ * (you will need to reboot afterwards) */ /* #define BNX2X_STOP_ON_ERROR */ -#define DRV_MODULE_VERSION "1.52.53-3" -#define DRV_MODULE_RELDATE "2010/18/04" +#define DRV_MODULE_VERSION "1.52.53-4" +#define DRV_MODULE_RELDATE "2010/16/08" #define BNX2X_BC_VER 0x040200 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) -- cgit v0.10.2 From 2928db4c3c62552d3caf9ab53ccc6f7ae9865a23 Mon Sep 17 00:00:00 2001 From: Andre Detsch Date: Tue, 17 Aug 2010 05:49:12 +0000 Subject: ehea: Fix synchronization between HW and SW send queue ehea: Fix synchronization between HW and SW send queue When memory is added to / removed from a partition via the Memory DLPAR mechanism, the eHEA driver has to do a couple of things to reflect the memory change in its own IO address translation tables. This involves stopping and restarting the HW queues. During this operation, it is possible that HW and SW pointer into these queues get out of sync. This results in a situation where packets that are attached to a send queue are not transmitted immediately, but delayed until further X packets have been put on the queue. This patch detects such loss of synchronization, and resets the ehea port when needed. Signed-off-by: Jan-Bernd Themann Signed-off-by: Andre Detsch Signed-off-by: David S. Miller diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index 0060e42..2ce67f6 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h @@ -40,7 +40,7 @@ #include #define DRV_NAME "ehea" -#define DRV_VERSION "EHEA_0105" +#define DRV_VERSION "EHEA_0106" /* eHEA capability flags */ #define DLPAR_PORT_ADD_REM 1 @@ -400,6 +400,7 @@ struct ehea_port_res { u32 poll_counter; struct net_lro_mgr lro_mgr; struct net_lro_desc lro_desc[MAX_LRO_DESCRIPTORS]; + int sq_restart_flag; }; diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 3beba70..adb5994 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -776,6 +776,53 @@ static int ehea_proc_rwqes(struct net_device *dev, return processed; } +#define SWQE_RESTART_CHECK 0xdeadbeaff00d0000ull + +static void reset_sq_restart_flag(struct ehea_port *port) +{ + int i; + + for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) { + struct ehea_port_res *pr = &port->port_res[i]; + pr->sq_restart_flag = 0; + } +} + +static void check_sqs(struct ehea_port *port) +{ + struct ehea_swqe *swqe; + int swqe_index; + int i, k; + + for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) { + struct ehea_port_res *pr = &port->port_res[i]; + k = 0; + swqe = ehea_get_swqe(pr->qp, &swqe_index); + memset(swqe, 0, SWQE_HEADER_SIZE); + atomic_dec(&pr->swqe_avail); + + swqe->tx_control |= EHEA_SWQE_PURGE; + swqe->wr_id = SWQE_RESTART_CHECK; + swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION; + swqe->tx_control |= EHEA_SWQE_IMM_DATA_PRESENT; + swqe->immediate_data_length = 80; + + ehea_post_swqe(pr->qp, swqe); + + while (pr->sq_restart_flag == 0) { + msleep(5); + if (++k == 100) { + ehea_error("HW/SW queues out of sync"); + ehea_schedule_port_reset(pr->port); + return; + } + } + } + + return; +} + + static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota) { struct sk_buff *skb; @@ -793,6 +840,13 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota) cqe_counter++; rmb(); + + if (cqe->wr_id == SWQE_RESTART_CHECK) { + pr->sq_restart_flag = 1; + swqe_av++; + break; + } + if (cqe->status & EHEA_CQE_STAT_ERR_MASK) { ehea_error("Bad send completion status=0x%04X", cqe->status); @@ -2675,8 +2729,10 @@ static void ehea_flush_sq(struct ehea_port *port) int k = 0; while (atomic_read(&pr->swqe_avail) < swqe_max) { msleep(5); - if (++k == 20) + if (++k == 20) { + ehea_error("WARNING: sq not flushed completely"); break; + } } } } @@ -2917,6 +2973,7 @@ static void ehea_rereg_mrs(struct work_struct *work) port_napi_disable(port); mutex_unlock(&port->port_lock); } + reset_sq_restart_flag(port); } /* Unregister old memory region */ @@ -2951,6 +3008,7 @@ static void ehea_rereg_mrs(struct work_struct *work) mutex_lock(&port->port_lock); port_napi_enable(port); ret = ehea_restart_qps(dev); + check_sqs(port); if (!ret) netif_wake_queue(dev); mutex_unlock(&port->port_lock); -- cgit v0.10.2 From 0645bab7da3cb021157e5c661ef35f1d1226785a Mon Sep 17 00:00:00 2001 From: Robert Jennings Date: Tue, 17 Aug 2010 09:15:45 +0000 Subject: ibmveth: Fix opps during MTU change on an active device This fixes the following opps which can occur when trying to deallocate receive buffer pools when changing the MTU of an active ibmveth device. Oops: Kernel access of bad area, sig: 11 [#1] NIP: d000000004db00e8 LR: d000000004db00ac CTR: 0000000000591038 REGS: c00000007fff39d0 TRAP: 0300 Not tainted (2.6.36-rc1) MSR: 8000000000009032 CR: 22248244 XER: 00000002 DAR: 0000000000000488, DSISR: 0000000042000000 TASK = c00000007c463790[6531] 'netserver' THREAD: c00000007a154000 CPU: 0 GPR00: 0000000000000000 c00000007fff3c50 d000000004dbd360 0000000000000001 GPR04: 0000000000000001 1fffffffffffffff 000000000000043c c00000007a8e9f60 GPR08: c00000007a8e9e20 0000000000000245 0000000000000488 0000000000000000 GPR12: 00000000000000c0 c000000006d70000 c00000007bfec098 c00000007bfebc2c GPR16: c00000007a157c78 0000000000000000 0000000000000001 0000000000000000 GPR20: 0000000000000001 0000000000000010 c000000000b51180 c00000007a8e9d90 GPR24: c00000007a8e9da0 c00000007a8e9580 00000000000005ea 00000000000002ff GPR28: 0000000000000004 0000000000000080 c000000000a946f8 c00000007a8e9d80 NIP [d000000004db00e8] .ibmveth_remove_buffer_from_pool+0xe8/0x130 [ibmveth] LR [d000000004db00ac] .ibmveth_remove_buffer_from_pool+0xac/0x130 [ibmveth] Call Trace: [c00000007fff3c50] [d000000004db00ac] .ibmveth_remove_buffer_from_pool+0xac/0x130 [ibmveth] (unreliable) [c00000007fff3cf0] [d000000004db31dc] .ibmveth_poll+0x30c/0x460 [ibmveth] [c00000007fff3dd0] [c00000000042c4b8] .net_rx_action+0x178/0x278 [c00000007fff3eb0] [c000000000093cf0] .__do_softirq+0x118/0x1f8 [c00000007fff3f90] [c00000000002ab3c] .call_do_softirq+0x14/0x24 [c00000007a157600] [c00000000000e3e4] .do_softirq+0xec/0x110 [c00000007a1576a0] [c000000000093394] .local_bh_enable_ip+0xb4/0xe0 [c00000007a157720] [c0000000004f0bac] ._raw_spin_unlock_bh+0x3c/0x50 [c00000007a157790] [c0000000004186e0] .release_sock+0x158/0x188 [c00000007a157840] [c000000000479660] .tcp_recvmsg+0x560/0x9b8 [c00000007a157970] [c0000000004a0d78] .inet_recvmsg+0x80/0xd8 [c00000007a157a00] [c000000000413e28] .sock_recvmsg+0x128/0x178 [c00000007a157bf0] [c0000000004164ac] .SyS_recvfrom+0xb4/0x148 [c00000007a157d70] [c000000000411f3c] .SyS_socketcall+0x274/0x360 [c00000007a157e30] [c0000000000085b4] syscall_exit+0x0/0x40 Reported-by: Rafael Camarda Silva Folco Signed-off-by: Robert Jennings Acked-by: Brian King Signed-off-by: David S. Miller diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 2602852..4734c93 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1113,7 +1113,8 @@ static int ibmveth_change_mtu(struct net_device *dev, int new_mtu) struct ibmveth_adapter *adapter = netdev_priv(dev); struct vio_dev *viodev = adapter->vdev; int new_mtu_oh = new_mtu + IBMVETH_BUFF_OH; - int i; + int i, rc; + int need_restart = 0; if (new_mtu < IBMVETH_MAX_MTU) return -EINVAL; @@ -1127,35 +1128,32 @@ static int ibmveth_change_mtu(struct net_device *dev, int new_mtu) /* Deactivate all the buffer pools so that the next loop can activate only the buffer pools necessary to hold the new MTU */ - for (i = 0; i < IbmVethNumBufferPools; i++) - if (adapter->rx_buff_pool[i].active) { - ibmveth_free_buffer_pool(adapter, - &adapter->rx_buff_pool[i]); - adapter->rx_buff_pool[i].active = 0; - } + if (netif_running(adapter->netdev)) { + need_restart = 1; + adapter->pool_config = 1; + ibmveth_close(adapter->netdev); + adapter->pool_config = 0; + } /* Look for an active buffer pool that can hold the new MTU */ for(i = 0; irx_buff_pool[i].active = 1; if (new_mtu_oh < adapter->rx_buff_pool[i].buff_size) { - if (netif_running(adapter->netdev)) { - adapter->pool_config = 1; - ibmveth_close(adapter->netdev); - adapter->pool_config = 0; - dev->mtu = new_mtu; - vio_cmo_set_dev_desired(viodev, - ibmveth_get_desired_dma - (viodev)); - return ibmveth_open(adapter->netdev); - } dev->mtu = new_mtu; vio_cmo_set_dev_desired(viodev, ibmveth_get_desired_dma (viodev)); + if (need_restart) { + return ibmveth_open(adapter->netdev); + } return 0; } } + + if (need_restart && (rc = ibmveth_open(adapter->netdev))) + return rc; + return -EINVAL; } -- cgit v0.10.2 From 0ac820eebe9008094040955d294ef7b33b418413 Mon Sep 17 00:00:00 2001 From: Phil Oester Date: Tue, 17 Aug 2010 18:45:08 +0000 Subject: vlan: Match underlying dev carrier on vlan add When adding a new vlan, if the underlying interface has no carrier, then the newly added vlan interface should also have no carrier. At present, this is not true - the newly added vlan is added with carrier up. Fix by checking state of real device. Signed-off-by: Phil Oester Signed-off-by: David S. Miller diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 3d59c9b..3bccdd1 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -510,7 +510,8 @@ static int vlan_dev_open(struct net_device *dev) if (vlan->flags & VLAN_FLAG_GVRP) vlan_gvrp_request_join(dev); - netif_carrier_on(dev); + if (netif_carrier_ok(real_dev)) + netif_carrier_on(dev); return 0; clear_allmulti: -- cgit v0.10.2 From 4be353d5169ef2477814b35fe46734a51dcecd09 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Tue, 17 Aug 2010 20:51:51 +0000 Subject: netxen: fix inconsistent lock state Spin lock rds_ring->lock is used in poll routine, so other users should use spin_lock_bh(). While posting rx buffers from netxen_nic_attach, rds_ring->lock is not required, so cleaning it instead of fixing it by spin_lock_bh(). Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index c865dda..cabae7b 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -1805,8 +1805,6 @@ netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid, netxen_ctx_msg msg = 0; struct list_head *head; - spin_lock(&rds_ring->lock); - producer = rds_ring->producer; head = &rds_ring->free_list; @@ -1853,8 +1851,6 @@ netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid, NETXEN_RCV_PRODUCER_OFFSET), msg); } } - - spin_unlock(&rds_ring->lock); } static void -- cgit v0.10.2 From 772806bbbc5aa4ddf5ac0de57c1ee7c0ef94e490 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Tue, 17 Aug 2010 20:51:52 +0000 Subject: netxen: update version 4.0.74 Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index ffa1b9c..6dca357 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -53,8 +53,8 @@ #define _NETXEN_NIC_LINUX_MAJOR 4 #define _NETXEN_NIC_LINUX_MINOR 0 -#define _NETXEN_NIC_LINUX_SUBVERSION 73 -#define NETXEN_NIC_LINUX_VERSIONID "4.0.73" +#define _NETXEN_NIC_LINUX_SUBVERSION 74 +#define NETXEN_NIC_LINUX_VERSIONID "4.0.74" #define NETXEN_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c)) #define _major(v) (((v) >> 24) & 0xff) -- cgit v0.10.2 From 9c38657cfcb739b7dc4ce9065a85b4f0c195bef8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 19 Aug 2010 00:39:45 -0700 Subject: net: sh_eth: remove unused variable Signed-off-by: Kuninori Morimoto Signed-off-by: David S. Miller diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index f5a9eb1..79fd02b 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -1437,7 +1437,7 @@ static const struct net_device_ops sh_eth_netdev_ops = { static int sh_eth_drv_probe(struct platform_device *pdev) { - int ret, i, devno = 0; + int ret, devno = 0; struct resource *res; struct net_device *ndev = NULL; struct sh_eth_private *mdp; -- cgit v0.10.2 From 79c5f51c639021f7472591239c3867cee4b9ec02 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 18 Aug 2010 00:24:43 +0000 Subject: irda: fix a race in irlan_eth_xmit() After skb is queued, its illegal to dereference it. Cache skb->len into a temporary variable. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c index 9616c32..5bb8353 100644 --- a/net/irda/irlan/irlan_eth.c +++ b/net/irda/irlan/irlan_eth.c @@ -169,6 +169,7 @@ static netdev_tx_t irlan_eth_xmit(struct sk_buff *skb, { struct irlan_cb *self = netdev_priv(dev); int ret; + unsigned int len; /* skb headroom large enough to contain all IrDA-headers? */ if ((skb_headroom(skb) < self->max_header_size) || (skb_shared(skb))) { @@ -188,6 +189,7 @@ static netdev_tx_t irlan_eth_xmit(struct sk_buff *skb, dev->trans_start = jiffies; + len = skb->len; /* Now queue the packet in the transport layer */ if (self->use_udata) ret = irttp_udata_request(self->tsap_data, skb); @@ -209,7 +211,7 @@ static netdev_tx_t irlan_eth_xmit(struct sk_buff *skb, self->stats.tx_dropped++; } else { self->stats.tx_packets++; - self->stats.tx_bytes += skb->len; + self->stats.tx_bytes += len; } return NETDEV_TX_OK; -- cgit v0.10.2 From 1003201a73daed739747b9a6c2c39c57aad5878b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 18 Aug 2010 00:42:48 +0000 Subject: qlnic: fix a race in qlcnic_get_stats() Dont clear netdev->stats, it might give transient wrong values to concurrent stat readers. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index bf6d87a..213e365 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -1983,8 +1983,6 @@ static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev) struct qlcnic_adapter *adapter = netdev_priv(netdev); struct net_device_stats *stats = &netdev->stats; - memset(stats, 0, sizeof(*stats)); - stats->rx_packets = adapter->stats.rx_pkts + adapter->stats.lro_pkts; stats->tx_packets = adapter->stats.xmitfinished; stats->rx_bytes = adapter->stats.rxbytes + adapter->stats.lrobytes; -- cgit v0.10.2 From 502820a3161e2f228125977d133dd80eea2932d1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 18 Aug 2010 02:29:30 +0000 Subject: netxen: fix a race in netxen_nic_get_stats() Dont clear netdev->stats, it might give transient wrong values to concurrent stat readers. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index fd86e18..cb30df1 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -2032,8 +2032,6 @@ struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev) struct netxen_adapter *adapter = netdev_priv(netdev); struct net_device_stats *stats = &netdev->stats; - memset(stats, 0, sizeof(*stats)); - stats->rx_packets = adapter->stats.rx_pkts + adapter->stats.lro_pkts; stats->tx_packets = adapter->stats.xmitfinished; stats->rx_bytes = adapter->stats.rxbytes; -- cgit v0.10.2 From 8539992f6091eb8206c781421312157d0c282e6e Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 18 Aug 2010 00:26:34 +0000 Subject: ll_temac: Fix poll implementation Functions ll_temac_rx_irq and ll_temac_tx_irq have pointer to net_device as second parameter not pointer to temac_local. Signed-off-by: Michal Simek Signed-off-by: David S. Miller diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c index 4eea3f7..09b813f 100644 --- a/drivers/net/ll_temac_main.c +++ b/drivers/net/ll_temac_main.c @@ -902,8 +902,8 @@ temac_poll_controller(struct net_device *ndev) disable_irq(lp->tx_irq); disable_irq(lp->rx_irq); - ll_temac_rx_irq(lp->tx_irq, lp); - ll_temac_tx_irq(lp->rx_irq, lp); + ll_temac_rx_irq(lp->tx_irq, ndev); + ll_temac_tx_irq(lp->rx_irq, ndev); enable_irq(lp->tx_irq); enable_irq(lp->rx_irq); -- cgit v0.10.2 From 737480a0d525dae13306296da08029dff545bc72 Mon Sep 17 00:00:00 2001 From: KUMANO Syuhei Date: Sun, 15 Aug 2010 15:18:04 +0900 Subject: kprobes/x86: Fix the return address of multiple kretprobes Fix the return address of subsequent kretprobes when multiple kretprobes are set on the same function. For example: # cd /sys/kernel/debug/tracing # echo "r:event1 sys_symlink" > kprobe_events # echo "r:event2 sys_symlink" >> kprobe_events # echo 1 > events/kprobes/enable # ln -s /tmp/foo /tmp/bar (without this patch) # cat trace ln-897 [000] 20404.133727: event1: (kretprobe_trampoline+0x0/0x4c <- sys_symlink) ln-897 [000] 20404.133747: event2: (system_call_fastpath+0x16/0x1b <- sys_symlink) (with this patch) # cat trace ln-740 [000] 13799.491076: event1: (system_call_fastpath+0x16/0x1b <- sys_symlink) ln-740 [000] 13799.491096: event2: (system_call_fastpath+0x16/0x1b <- sys_symlink) Signed-off-by: KUMANO Syuhei Reviewed-by: Masami Hiramatsu Cc: Frederic Weisbecker Cc: Ananth N Mavinakayanahalli Cc: Peter Zijlstra Cc: YOSHIFUJI Hideaki LKML-Reference: <1281853084.3254.11.camel@camp10-laptop> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c index 1bfb6cf..770ebfb 100644 --- a/arch/x86/kernel/kprobes.c +++ b/arch/x86/kernel/kprobes.c @@ -709,6 +709,7 @@ static __used __kprobes void *trampoline_handler(struct pt_regs *regs) struct hlist_node *node, *tmp; unsigned long flags, orig_ret_address = 0; unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline; + kprobe_opcode_t *correct_ret_addr = NULL; INIT_HLIST_HEAD(&empty_rp); kretprobe_hash_lock(current, &head, &flags); @@ -740,14 +741,34 @@ static __used __kprobes void *trampoline_handler(struct pt_regs *regs) /* another task is sharing our hash bucket */ continue; + orig_ret_address = (unsigned long)ri->ret_addr; + + if (orig_ret_address != trampoline_address) + /* + * This is the real return address. Any other + * instances associated with this task are for + * other calls deeper on the call stack + */ + break; + } + + kretprobe_assert(ri, orig_ret_address, trampoline_address); + + correct_ret_addr = ri->ret_addr; + hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { + if (ri->task != current) + /* another task is sharing our hash bucket */ + continue; + + orig_ret_address = (unsigned long)ri->ret_addr; if (ri->rp && ri->rp->handler) { __get_cpu_var(current_kprobe) = &ri->rp->kp; get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE; + ri->ret_addr = correct_ret_addr; ri->rp->handler(ri, regs); __get_cpu_var(current_kprobe) = NULL; } - orig_ret_address = (unsigned long)ri->ret_addr; recycle_rp_inst(ri, &empty_rp); if (orig_ret_address != trampoline_address) @@ -759,8 +780,6 @@ static __used __kprobes void *trampoline_handler(struct pt_regs *regs) break; } - kretprobe_assert(ri, orig_ret_address, trampoline_address); - kretprobe_hash_unlock(current, &flags); hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { -- cgit v0.10.2 From ede1b4290781ae82ccf0f2ecc6dada8d3dd35779 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Wed, 18 Aug 2010 15:33:13 -0700 Subject: tracing: Fix timer tracing PowerTOP would like to be able to trace timers. Unfortunately, the current timer tracing is not very useful: the actual timer function is not recorded in the trace at the start of timer execution. Although this is recorded for timer "start" time (when it gets armed), this is not useful; most timers get started early, and a tracer like PowerTOP will never see this event, but will only see the actual running of the timer. This patch just adds the function to the timer tracing; I've verified with PowerTOP that now it can get useful information about timers. Signed-off-by: Arjan van de Ven Cc: xiaoguangrong@cn.fujitsu.com Cc: Steven Rostedt Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: # .35.x, .34.x, .33.x LKML-Reference: <4C6C5FA9.3000405@linux.intel.com> Signed-off-by: Ingo Molnar diff --git a/include/trace/events/timer.h b/include/trace/events/timer.h index c624126..425bcfe 100644 --- a/include/trace/events/timer.h +++ b/include/trace/events/timer.h @@ -81,14 +81,16 @@ TRACE_EVENT(timer_expire_entry, TP_STRUCT__entry( __field( void *, timer ) __field( unsigned long, now ) + __field( void *, function) ), TP_fast_assign( __entry->timer = timer; __entry->now = jiffies; + __entry->function = timer->function; ), - TP_printk("timer=%p now=%lu", __entry->timer, __entry->now) + TP_printk("timer=%p function=%pf now=%lu", __entry->timer, __entry->function,__entry->now) ); /** @@ -200,14 +202,16 @@ TRACE_EVENT(hrtimer_expire_entry, TP_STRUCT__entry( __field( void *, hrtimer ) __field( s64, now ) + __field( void *, function) ), TP_fast_assign( __entry->hrtimer = hrtimer; __entry->now = now->tv64; + __entry->function = hrtimer->function; ), - TP_printk("hrtimer=%p now=%llu", __entry->hrtimer, + TP_printk("hrtimer=%p function=%pf now=%llu", __entry->hrtimer, __entry->function, (unsigned long long)ktime_to_ns((ktime_t) { .tv64 = __entry->now })) ); -- cgit v0.10.2 From 065a1ed8de85583888b3d4f22c64b534a1fbdaaa Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 18 Aug 2010 11:25:04 -0700 Subject: mtd: nand: Fix regression in BBM detection Commit c7b28e25cb9beb943aead770ff14551b55fa8c79 ("mtd: nand: refactor BB marker detection") caused a regression in detection of factory-set bad block markers, especially for certain small-page NAND. This fix removes some unneeded constraints on using NAND_SMALL_BADBLOCK_POS, making the detection code more correct. This regression can be seen, for example, in Hynix HY27US081G1M and similar. Signed-off-by: Brian Norris Tested-by: Michael Guntsche Signed-off-by: David Woodhouse diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index a3c7473..a22ed7b 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2934,14 +2934,10 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 32 - 1; /* Set the bad block position */ - if (!(busw & NAND_BUSWIDTH_16) && (*maf_id == NAND_MFR_STMICRO || - (*maf_id == NAND_MFR_SAMSUNG && - mtd->writesize == 512) || - *maf_id == NAND_MFR_AMD)) - chip->badblockpos = NAND_SMALL_BADBLOCK_POS; - else + if (mtd->writesize > 512 || (busw & NAND_BUSWIDTH_16)) chip->badblockpos = NAND_LARGE_BADBLOCK_POS; - + else + chip->badblockpos = NAND_SMALL_BADBLOCK_POS; /* Get chip options, preserve non chip based options */ chip->options &= ~NAND_CHIPOPTIONS_MSK; -- cgit v0.10.2 From 019408f9b89c68cd7b8ddb904960dc17ccf7e531 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Thu, 19 Aug 2010 14:15:32 -0700 Subject: sparc64: Fill a missing delay slot. If the code were already aligned to 64 bytes, wr instruction would be executed twice --- once in delay slot and once in the jump target. Signed-off-by: Mikulas Patocka Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/system_64.h b/arch/sparc/include/asm/system_64.h index d24cfe1..e3b65d8 100644 --- a/arch/sparc/include/asm/system_64.h +++ b/arch/sparc/include/asm/system_64.h @@ -106,6 +106,7 @@ do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \ */ #define write_pic(__p) \ __asm__ __volatile__("ba,pt %%xcc, 99f\n\t" \ + " nop\n\t" \ ".align 64\n" \ "99:wr %0, 0x0, %%pic\n\t" \ "rd %%pic, %%g0" : : "r" (__p)) -- cgit v0.10.2 From d7c53c9e822a4fefa13a0cae76f3190bfd0d5c11 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 19 Aug 2010 20:10:29 +0200 Subject: x86, hotplug: Serialize CPU hotplug to avoid bringup concurrency issues When testing cpu hotplug code on 32-bit we kept hitting the "CPU%d: Stuck ??" message due to multiple cores concurrently accessing the cpu_callin_mask, among others. Since these codepaths are not protected from concurrent access due to the fact that there's no sane reason for making an already complex code unnecessarily more complex - we hit the issue only when insanely switching cores off- and online - serialize hotplugging cores on the sysfs level and be done with it. [ v2.1: fix !HOTPLUG_CPU build ] Cc: Signed-off-by: Borislav Petkov LKML-Reference: <20100819181029.GC17171@aftab> Signed-off-by: H. Peter Anvin diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index a84fc34..ac7827f 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -245,6 +245,11 @@ config ARCH_HWEIGHT_CFLAGS config KTIME_SCALAR def_bool X86_32 + +config ARCH_CPU_PROBE_RELEASE + def_bool y + depends on HOTPLUG_CPU + source "init/Kconfig" source "kernel/Kconfig.freezer" diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index abf4a86..8b3bfc4 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -90,6 +90,25 @@ DEFINE_PER_CPU(int, cpu_state) = { 0 }; static DEFINE_PER_CPU(struct task_struct *, idle_thread_array); #define get_idle_for_cpu(x) (per_cpu(idle_thread_array, x)) #define set_idle_for_cpu(x, p) (per_cpu(idle_thread_array, x) = (p)) + +/* + * We need this for trampoline_base protection from concurrent accesses when + * off- and onlining cores wildly. + */ +static DEFINE_MUTEX(x86_cpu_hotplug_driver_mutex); + +void cpu_hotplug_driver_lock() +{ + mutex_lock(&x86_cpu_hotplug_driver_mutex); +} + +void cpu_hotplug_driver_unlock() +{ + mutex_unlock(&x86_cpu_hotplug_driver_mutex); +} + +ssize_t arch_cpu_probe(const char *buf, size_t count) { return -1; } +ssize_t arch_cpu_release(const char *buf, size_t count) { return -1; } #else static struct task_struct *idle_thread_array[NR_CPUS] __cpuinitdata ; #define get_idle_for_cpu(x) (idle_thread_array[(x)]) -- cgit v0.10.2 From 2cbeb4efc2b9739fe6019b613ae658bd2119a3eb Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Mon, 16 Aug 2010 11:54:36 -0400 Subject: drm/radeon/kms: fix GTT/VRAM overlapping test GTT/VRAM overlapping test had a typo which leaded to not detecting case when vram_end > gtt_end. This patch fix the logic and should fix #16574 Signed-off-by: Jerome Glisse Cc: stable@kernel.org Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 4f7a170..69b3c22 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -199,7 +199,7 @@ void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 mc->mc_vram_size = mc->aper_size; } mc->vram_end = mc->vram_start + mc->mc_vram_size - 1; - if (rdev->flags & RADEON_IS_AGP && mc->vram_end > mc->gtt_start && mc->vram_end <= mc->gtt_end) { + if (rdev->flags & RADEON_IS_AGP && mc->vram_end > mc->gtt_start && mc->vram_start <= mc->gtt_end) { dev_warn(rdev->dev, "limiting VRAM to PCI aperture size\n"); mc->real_vram_size = mc->aper_size; mc->mc_vram_size = mc->aper_size; -- cgit v0.10.2 From 1d978dac7e99bd551df5001f0cc92369054dca0d Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 15 Aug 2010 14:11:24 +0200 Subject: drm/radeon: Fix stack data leak Always zero-init a structure on the stack which is returned by a function. Otherwise you may leak random stack data from previous function calls. This fixes the following warning I was seeing: CC [M] drivers/gpu/drm/radeon/radeon_atombios.o drivers/gpu/drm/radeon/radeon_atombios.c: In function "radeon_atom_get_hpd_info_from_gpio": drivers/gpu/drm/radeon/radeon_atombios.c:261: warning: "hpd.plugged_state" is used uninitialized in this function Signed-off-by: Jean Delvare Cc: David Airlie Cc: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 6d30868..4a4225e 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -226,6 +226,8 @@ static struct radeon_hpd radeon_atom_get_hpd_info_from_gpio(struct radeon_device struct radeon_hpd hpd; u32 reg; + memset(&hpd, 0, sizeof(struct radeon_hpd)); + if (ASIC_IS_DCE4(rdev)) reg = EVERGREEN_DC_GPIO_HPD_A; else -- cgit v0.10.2 From fbee67a65d16c431ae3c389db13688c6e1b1b9d8 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 16 Aug 2010 12:44:47 -0400 Subject: drm/radeon/kms: DCE3/4 AdjustPixelPll updates Add options necessary bits for: - SS on DP - SS on LVDS - set clocks right for DP - deep color on hdmi (needs additional encoder and edid work as well) Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 12ad512..577239a 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -471,6 +471,8 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, struct radeon_encoder *radeon_encoder = NULL; u32 adjusted_clock = mode->clock; int encoder_mode = 0; + u32 dp_clock = mode->clock; + int bpc = 8; /* reset the pll flags */ pll->flags = 0; @@ -513,6 +515,17 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, if (encoder->crtc == crtc) { radeon_encoder = to_radeon_encoder(encoder); encoder_mode = atombios_get_encoder_mode(encoder); + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) { + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + if (connector) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *dig_connector = + radeon_connector->con_priv; + + dp_clock = dig_connector->dp_clock; + } + } + if (ASIC_IS_AVIVO(rdev)) { /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) @@ -555,6 +568,14 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, args.v1.usPixelClock = cpu_to_le16(mode->clock / 10); args.v1.ucTransmitterID = radeon_encoder->encoder_id; args.v1.ucEncodeMode = encoder_mode; + if (encoder_mode == ATOM_ENCODER_MODE_DP) { + /* may want to enable SS on DP eventually */ + /* args.v1.ucConfig |= + ADJUST_DISPLAY_CONFIG_SS_ENABLE;*/ + } else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) { + args.v1.ucConfig |= + ADJUST_DISPLAY_CONFIG_SS_ENABLE; + } atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); @@ -568,10 +589,20 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - if (encoder_mode == ATOM_ENCODER_MODE_DP) + if (encoder_mode == ATOM_ENCODER_MODE_DP) { + /* may want to enable SS on DP/eDP eventually */ + /*args.v3.sInput.ucDispPllConfig |= + DISPPLL_CONFIG_SS_ENABLE;*/ args.v3.sInput.ucDispPllConfig |= DISPPLL_CONFIG_COHERENT_MODE; - else { + /* 16200 or 27000 */ + args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); + } else { + if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { + /* deep color support */ + args.v3.sInput.usPixelClock = + cpu_to_le16((mode->clock * bpc / 8) / 10); + } if (dig->coherent_mode) args.v3.sInput.ucDispPllConfig |= DISPPLL_CONFIG_COHERENT_MODE; @@ -580,13 +611,19 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, DISPPLL_CONFIG_DUAL_LINK; } } else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { - /* may want to enable SS on DP/eDP eventually */ - /*args.v3.sInput.ucDispPllConfig |= - DISPPLL_CONFIG_SS_ENABLE;*/ - if (encoder_mode == ATOM_ENCODER_MODE_DP) + if (encoder_mode == ATOM_ENCODER_MODE_DP) { + /* may want to enable SS on DP/eDP eventually */ + /*args.v3.sInput.ucDispPllConfig |= + DISPPLL_CONFIG_SS_ENABLE;*/ args.v3.sInput.ucDispPllConfig |= DISPPLL_CONFIG_COHERENT_MODE; - else { + /* 16200 or 27000 */ + args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); + } else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) { + /* want to enable SS on LVDS eventually */ + /*args.v3.sInput.ucDispPllConfig |= + DISPPLL_CONFIG_SS_ENABLE;*/ + } else { if (mode->clock > 165000) args.v3.sInput.ucDispPllConfig |= DISPPLL_CONFIG_DUAL_LINK; -- cgit v0.10.2 From 5137ee940c3e593ae5578a7a12a604eb8f239ac0 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 12 Aug 2010 18:58:47 -0400 Subject: drm/radeon/kms: rework encoder handling On most newer asics, digital encoders have two links each and they can be used independantly. As such, treat them as separate encoders otherwise the individual links will not get programmed properly at modeset time. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 36e0d4b..4e7778d 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -610,7 +610,7 @@ void dp_link_train(struct drm_encoder *encoder, enc_id |= ATOM_DP_CONFIG_DIG2_ENCODER; else enc_id |= ATOM_DP_CONFIG_DIG1_ENCODER; - if (dig_connector->linkb) + if (dig->linkb) enc_id |= ATOM_DP_CONFIG_LINK_B; else enc_id |= ATOM_DP_CONFIG_LINK_A; diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 4a4225e..b015915 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -32,11 +32,11 @@ /* from radeon_encoder.c */ extern uint32_t -radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device, - uint8_t dac); +radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device, + uint8_t dac); extern void radeon_link_encoder_connector(struct drm_device *dev); extern void -radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, +radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t supported_device); /* from radeon_connector.c */ @@ -46,14 +46,14 @@ radeon_add_atom_connector(struct drm_device *dev, uint32_t supported_device, int connector_type, struct radeon_i2c_bus_rec *i2c_bus, - bool linkb, uint32_t igp_lane_info, + uint32_t igp_lane_info, uint16_t connector_object_id, struct radeon_hpd *hpd, struct radeon_router *router); /* from radeon_legacy_encoder.c */ extern void -radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_id, +radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t supported_device); union atom_supported_devices { @@ -479,7 +479,6 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) int i, j, k, path_size, device_support; int connector_type; u16 igp_lane_info, conn_id, connector_object_id; - bool linkb; struct radeon_i2c_bus_rec ddc_bus; struct radeon_router router; struct radeon_gpio_rec gpio; @@ -512,7 +511,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) addr += path_size; path = (ATOM_DISPLAY_OBJECT_PATH *) addr; path_size += le16_to_cpu(path->usSize); - linkb = false; + if (device_support & le16_to_cpu(path->usDeviceTag)) { uint8_t con_obj_id, con_obj_num, con_obj_type; @@ -603,13 +602,10 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT; if (grph_obj_type == GRAPH_OBJECT_TYPE_ENCODER) { - if (grph_obj_num == 2) - linkb = true; - else - linkb = false; + u16 encoder_obj = le16_to_cpu(path->usGraphicObjIds[j]); radeon_add_atom_encoder(dev, - grph_obj_id, + encoder_obj, le16_to_cpu (path-> usDeviceTag)); @@ -746,7 +742,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) le16_to_cpu(path-> usDeviceTag), connector_type, &ddc_bus, - linkb, igp_lane_info, + igp_lane_info, connector_object_id, &hpd, &router); @@ -935,13 +931,13 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct if (ASIC_IS_AVIVO(rdev) || radeon_r4xx_atom) radeon_add_atom_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, (1 << i), dac), (1 << i)); else radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, (1 << i), dac), (1 << i)); @@ -998,7 +994,7 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct bios_connectors[i]. connector_type, &bios_connectors[i].ddc_bus, - false, 0, + 0, connector_object_id, &bios_connectors[i].hpd, &router); @@ -1307,6 +1303,7 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct union lvds_info *lvds_info; uint8_t frev, crev; struct radeon_encoder_atom_dig *lvds = NULL; + int encoder_enum = (encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT; if (atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset)) { @@ -1370,6 +1367,12 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct } encoder->native_mode = lvds->native_mode; + + if (encoder_enum == 2) + lvds->linkb = true; + else + lvds->linkb = false; + } return lvds; } diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 885dcfa..bd74e42 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -39,8 +39,8 @@ /* from radeon_encoder.c */ extern uint32_t -radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device, - uint8_t dac); +radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device, + uint8_t dac); extern void radeon_link_encoder_connector(struct drm_device *dev); /* from radeon_connector.c */ @@ -55,7 +55,7 @@ radeon_add_legacy_connector(struct drm_device *dev, /* from radeon_legacy_encoder.c */ extern void -radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_id, +radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t supported_device); /* old legacy ATI BIOS routines */ @@ -1505,7 +1505,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT1_SUPPORT, 1), ATOM_DEVICE_CRT1_SUPPORT); @@ -1520,7 +1520,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_NONE_DETECTED, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_LCD1_SUPPORT, 0), ATOM_DEVICE_LCD1_SUPPORT); @@ -1535,7 +1535,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT1_SUPPORT, 1), ATOM_DEVICE_CRT1_SUPPORT); @@ -1550,12 +1550,12 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0); hpd.hpd = RADEON_HPD_1; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_DFP1_SUPPORT, 0), ATOM_DEVICE_DFP1_SUPPORT); radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT2_SUPPORT, 2), ATOM_DEVICE_CRT2_SUPPORT); @@ -1571,7 +1571,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT1_SUPPORT, 1), ATOM_DEVICE_CRT1_SUPPORT); @@ -1588,7 +1588,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c.valid = false; hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_TV1_SUPPORT, 2), ATOM_DEVICE_TV1_SUPPORT); @@ -1607,7 +1607,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_LCD1_SUPPORT, 0), ATOM_DEVICE_LCD1_SUPPORT); @@ -1619,7 +1619,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT2_SUPPORT, 2), ATOM_DEVICE_CRT2_SUPPORT); @@ -1631,7 +1631,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c.valid = false; hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_TV1_SUPPORT, 2), ATOM_DEVICE_TV1_SUPPORT); @@ -1648,7 +1648,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_LCD1_SUPPORT, 0), ATOM_DEVICE_LCD1_SUPPORT); @@ -1660,12 +1660,12 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0); hpd.hpd = RADEON_HPD_2; /* ??? */ radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_DFP2_SUPPORT, 0), ATOM_DEVICE_DFP2_SUPPORT); radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT1_SUPPORT, 1), ATOM_DEVICE_CRT1_SUPPORT); @@ -1680,7 +1680,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c.valid = false; hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_TV1_SUPPORT, 2), ATOM_DEVICE_TV1_SUPPORT); @@ -1697,7 +1697,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_LCD1_SUPPORT, 0), ATOM_DEVICE_LCD1_SUPPORT); @@ -1709,12 +1709,12 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0); hpd.hpd = RADEON_HPD_1; /* ??? */ radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_DFP1_SUPPORT, 0), ATOM_DEVICE_DFP1_SUPPORT); radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT1_SUPPORT, 1), ATOM_DEVICE_CRT1_SUPPORT); @@ -1728,7 +1728,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c.valid = false; hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_TV1_SUPPORT, 2), ATOM_DEVICE_TV1_SUPPORT); @@ -1745,7 +1745,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_LCD1_SUPPORT, 0), ATOM_DEVICE_LCD1_SUPPORT); @@ -1757,7 +1757,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT1_SUPPORT, 1), ATOM_DEVICE_CRT1_SUPPORT); @@ -1769,7 +1769,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c.valid = false; hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_TV1_SUPPORT, 2), ATOM_DEVICE_TV1_SUPPORT); @@ -1786,12 +1786,12 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0); hpd.hpd = RADEON_HPD_2; /* ??? */ radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_DFP2_SUPPORT, 0), ATOM_DEVICE_DFP2_SUPPORT); radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT2_SUPPORT, 2), ATOM_DEVICE_CRT2_SUPPORT); @@ -1806,7 +1806,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c.valid = false; hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_TV1_SUPPORT, 2), ATOM_DEVICE_TV1_SUPPORT); @@ -1823,12 +1823,12 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0); hpd.hpd = RADEON_HPD_1; /* ??? */ radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_DFP1_SUPPORT, 0), ATOM_DEVICE_DFP1_SUPPORT); radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT2_SUPPORT, 2), ATOM_DEVICE_CRT2_SUPPORT); @@ -1842,7 +1842,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c.valid = false; hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_TV1_SUPPORT, 2), ATOM_DEVICE_TV1_SUPPORT); @@ -1859,7 +1859,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0); hpd.hpd = RADEON_HPD_1; /* ??? */ radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_DFP1_SUPPORT, 0), ATOM_DEVICE_DFP1_SUPPORT); @@ -1871,7 +1871,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT2_SUPPORT, 2), ATOM_DEVICE_CRT2_SUPPORT); @@ -1883,7 +1883,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c.valid = false; hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_TV1_SUPPORT, 2), ATOM_DEVICE_TV1_SUPPORT); @@ -1900,7 +1900,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT1_SUPPORT, 1), ATOM_DEVICE_CRT1_SUPPORT); @@ -1912,7 +1912,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT2_SUPPORT, 2), ATOM_DEVICE_CRT2_SUPPORT); @@ -1924,7 +1924,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c.valid = false; hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_TV1_SUPPORT, 2), ATOM_DEVICE_TV1_SUPPORT); @@ -1941,7 +1941,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT1_SUPPORT, 1), ATOM_DEVICE_CRT1_SUPPORT); @@ -1952,7 +1952,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT2_SUPPORT, 2), ATOM_DEVICE_CRT2_SUPPORT); @@ -2109,7 +2109,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) else devices = ATOM_DEVICE_DFP1_SUPPORT; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id + radeon_get_encoder_enum (dev, devices, 0), devices); radeon_add_legacy_connector(dev, i, devices, @@ -2123,7 +2123,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) if (tmp & 0x1) { devices = ATOM_DEVICE_CRT2_SUPPORT; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id + radeon_get_encoder_enum (dev, ATOM_DEVICE_CRT2_SUPPORT, 2), @@ -2131,7 +2131,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) } else { devices = ATOM_DEVICE_CRT1_SUPPORT; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id + radeon_get_encoder_enum (dev, ATOM_DEVICE_CRT1_SUPPORT, 1), @@ -2151,7 +2151,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) if (tmp & 0x1) { devices |= ATOM_DEVICE_CRT2_SUPPORT; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id + radeon_get_encoder_enum (dev, ATOM_DEVICE_CRT2_SUPPORT, 2), @@ -2159,7 +2159,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) } else { devices |= ATOM_DEVICE_CRT1_SUPPORT; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id + radeon_get_encoder_enum (dev, ATOM_DEVICE_CRT1_SUPPORT, 1), @@ -2168,7 +2168,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) if ((tmp >> 4) & 0x1) { devices |= ATOM_DEVICE_DFP2_SUPPORT; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id + radeon_get_encoder_enum (dev, ATOM_DEVICE_DFP2_SUPPORT, 0), @@ -2177,7 +2177,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) } else { devices |= ATOM_DEVICE_DFP1_SUPPORT; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id + radeon_get_encoder_enum (dev, ATOM_DEVICE_DFP1_SUPPORT, 0), @@ -2202,7 +2202,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) connector_object_id = CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I; } radeon_add_legacy_encoder(dev, - radeon_get_encoder_id + radeon_get_encoder_enum (dev, devices, 0), devices); radeon_add_legacy_connector(dev, i, devices, @@ -2215,7 +2215,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) case CONNECTOR_CTV_LEGACY: case CONNECTOR_STV_LEGACY: radeon_add_legacy_encoder(dev, - radeon_get_encoder_id + radeon_get_encoder_enum (dev, ATOM_DEVICE_TV1_SUPPORT, 2), @@ -2242,12 +2242,12 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) DRM_DEBUG_KMS("Found DFP table, assuming DVI connector\n"); radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT1_SUPPORT, 1), ATOM_DEVICE_CRT1_SUPPORT); radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_DFP1_SUPPORT, 0), ATOM_DEVICE_DFP1_SUPPORT); @@ -2268,7 +2268,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) DRM_DEBUG_KMS("Found CRT table, assuming VGA connector\n"); if (crt_info) { radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT1_SUPPORT, 1), ATOM_DEVICE_CRT1_SUPPORT); @@ -2297,7 +2297,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) COMBIOS_LCD_DDC_INFO_TABLE); radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_LCD1_SUPPORT, 0), ATOM_DEVICE_LCD1_SUPPORT); @@ -2351,7 +2351,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) hpd.hpd = RADEON_HPD_NONE; ddc_i2c.valid = false; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id + radeon_get_encoder_enum (dev, ATOM_DEVICE_TV1_SUPPORT, 2), diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 47c4b27..20c353c 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -1037,7 +1037,6 @@ radeon_add_atom_connector(struct drm_device *dev, uint32_t supported_device, int connector_type, struct radeon_i2c_bus_rec *i2c_bus, - bool linkb, uint32_t igp_lane_info, uint16_t connector_object_id, struct radeon_hpd *hpd, @@ -1128,7 +1127,6 @@ radeon_add_atom_connector(struct drm_device *dev, radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); if (!radeon_dig_connector) goto failed; - radeon_dig_connector->linkb = linkb; radeon_dig_connector->igp_lane_info = igp_lane_info; radeon_connector->con_priv = radeon_dig_connector; drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); @@ -1158,7 +1156,6 @@ radeon_add_atom_connector(struct drm_device *dev, radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); if (!radeon_dig_connector) goto failed; - radeon_dig_connector->linkb = linkb; radeon_dig_connector->igp_lane_info = igp_lane_info; radeon_connector->con_priv = radeon_dig_connector; drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); @@ -1182,7 +1179,6 @@ radeon_add_atom_connector(struct drm_device *dev, radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); if (!radeon_dig_connector) goto failed; - radeon_dig_connector->linkb = linkb; radeon_dig_connector->igp_lane_info = igp_lane_info; radeon_connector->con_priv = radeon_dig_connector; drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type); @@ -1229,7 +1225,6 @@ radeon_add_atom_connector(struct drm_device *dev, radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); if (!radeon_dig_connector) goto failed; - radeon_dig_connector->linkb = linkb; radeon_dig_connector->igp_lane_info = igp_lane_info; radeon_connector->con_priv = radeon_dig_connector; drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type); diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 263c809..404320f 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -81,7 +81,7 @@ void radeon_setup_encoder_clones(struct drm_device *dev) } uint32_t -radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device, uint8_t dac) +radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device, uint8_t dac) { struct radeon_device *rdev = dev->dev_private; uint32_t ret = 0; @@ -97,59 +97,59 @@ radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device, uint8_t if ((rdev->family == CHIP_RS300) || (rdev->family == CHIP_RS400) || (rdev->family == CHIP_RS480)) - ret = ENCODER_OBJECT_ID_INTERNAL_DAC2; + ret = ENCODER_INTERNAL_DAC2_ENUM_ID1; else if (ASIC_IS_AVIVO(rdev)) - ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1; + ret = ENCODER_INTERNAL_KLDSCP_DAC1_ENUM_ID1; else - ret = ENCODER_OBJECT_ID_INTERNAL_DAC1; + ret = ENCODER_INTERNAL_DAC1_ENUM_ID1; break; case 2: /* dac b */ if (ASIC_IS_AVIVO(rdev)) - ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2; + ret = ENCODER_INTERNAL_KLDSCP_DAC2_ENUM_ID1; else { /*if (rdev->family == CHIP_R200) - ret = ENCODER_OBJECT_ID_INTERNAL_DVO1; + ret = ENCODER_INTERNAL_DVO1_ENUM_ID1; else*/ - ret = ENCODER_OBJECT_ID_INTERNAL_DAC2; + ret = ENCODER_INTERNAL_DAC2_ENUM_ID1; } break; case 3: /* external dac */ if (ASIC_IS_AVIVO(rdev)) - ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1; + ret = ENCODER_INTERNAL_KLDSCP_DVO1_ENUM_ID1; else - ret = ENCODER_OBJECT_ID_INTERNAL_DVO1; + ret = ENCODER_INTERNAL_DVO1_ENUM_ID1; break; } break; case ATOM_DEVICE_LCD1_SUPPORT: if (ASIC_IS_AVIVO(rdev)) - ret = ENCODER_OBJECT_ID_INTERNAL_LVTM1; + ret = ENCODER_INTERNAL_LVTM1_ENUM_ID1; else - ret = ENCODER_OBJECT_ID_INTERNAL_LVDS; + ret = ENCODER_INTERNAL_LVDS_ENUM_ID1; break; case ATOM_DEVICE_DFP1_SUPPORT: if ((rdev->family == CHIP_RS300) || (rdev->family == CHIP_RS400) || (rdev->family == CHIP_RS480)) - ret = ENCODER_OBJECT_ID_INTERNAL_DVO1; + ret = ENCODER_INTERNAL_DVO1_ENUM_ID1; else if (ASIC_IS_AVIVO(rdev)) - ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1; + ret = ENCODER_INTERNAL_KLDSCP_TMDS1_ENUM_ID1; else - ret = ENCODER_OBJECT_ID_INTERNAL_TMDS1; + ret = ENCODER_INTERNAL_TMDS1_ENUM_ID1; break; case ATOM_DEVICE_LCD2_SUPPORT: case ATOM_DEVICE_DFP2_SUPPORT: if ((rdev->family == CHIP_RS600) || (rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740)) - ret = ENCODER_OBJECT_ID_INTERNAL_DDI; + ret = ENCODER_INTERNAL_DDI_ENUM_ID1; else if (ASIC_IS_AVIVO(rdev)) - ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1; + ret = ENCODER_INTERNAL_KLDSCP_DVO1_ENUM_ID1; else - ret = ENCODER_OBJECT_ID_INTERNAL_DVO1; + ret = ENCODER_INTERNAL_DVO1_ENUM_ID1; break; case ATOM_DEVICE_DFP3_SUPPORT: - ret = ENCODER_OBJECT_ID_INTERNAL_LVTM1; + ret = ENCODER_INTERNAL_LVTM1_ENUM_ID1; break; } @@ -562,7 +562,7 @@ atombios_digital_setup(struct drm_encoder *encoder, int action) if (dig->lvds_misc & ATOM_PANEL_MISC_888RGB) args.v1.ucMisc |= (1 << 1); } else { - if (dig_connector->linkb) + if (dig->linkb) args.v1.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; if (radeon_encoder->pixel_clock > 165000) args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; @@ -601,7 +601,7 @@ atombios_digital_setup(struct drm_encoder *encoder, int action) args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4; } } else { - if (dig_connector->linkb) + if (dig->linkb) args.v2.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; if (radeon_encoder->pixel_clock > 165000) args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL; @@ -781,7 +781,7 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action) args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER3; break; } - if (dig_connector->linkb) + if (dig->linkb) args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKB; else args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKA; @@ -864,7 +864,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t else args.v3.ucLaneNum = 4; - if (dig_connector->linkb) { + if (dig->linkb) { args.v3.acConfig.ucLinkSel = 1; args.v3.acConfig.ucEncoderSel = 1; } @@ -904,7 +904,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t } } else if (ASIC_IS_DCE32(rdev)) { args.v2.acConfig.ucEncoderSel = dig->dig_encoder; - if (dig_connector->linkb) + if (dig->linkb) args.v2.acConfig.ucLinkSel = 1; switch (radeon_encoder->encoder_id) { @@ -954,7 +954,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t } } - if (dig_connector->linkb) + if (dig->linkb) args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB; else args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA; @@ -1290,24 +1290,22 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder) uint32_t dig_enc_in_use = 0; if (ASIC_IS_DCE4(rdev)) { - struct radeon_connector_atom_dig *dig_connector = - radeon_get_atom_connector_priv_from_encoder(encoder); - + dig = radeon_encoder->enc_priv; switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - if (dig_connector->linkb) + if (dig->linkb) return 1; else return 0; break; case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - if (dig_connector->linkb) + if (dig->linkb) return 3; else return 2; break; case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - if (dig_connector->linkb) + if (dig->linkb) return 5; else return 4; @@ -1641,6 +1639,7 @@ radeon_atombios_set_dac_info(struct radeon_encoder *radeon_encoder) struct radeon_encoder_atom_dig * radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder) { + int encoder_enum = (radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT; struct radeon_encoder_atom_dig *dig = kzalloc(sizeof(struct radeon_encoder_atom_dig), GFP_KERNEL); if (!dig) @@ -1650,11 +1649,16 @@ radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder) dig->coherent_mode = true; dig->dig_encoder = -1; + if (encoder_enum == 2) + dig->linkb = true; + else + dig->linkb = false; + return dig; } void -radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t supported_device) +radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t supported_device) { struct radeon_device *rdev = dev->dev_private; struct drm_encoder *encoder; @@ -1663,7 +1667,7 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t su /* see if we already added it */ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { radeon_encoder = to_radeon_encoder(encoder); - if (radeon_encoder->encoder_id == encoder_id) { + if (radeon_encoder->encoder_enum == encoder_enum) { radeon_encoder->devices |= supported_device; return; } @@ -1691,7 +1695,8 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t su radeon_encoder->enc_priv = NULL; - radeon_encoder->encoder_id = encoder_id; + radeon_encoder->encoder_enum = encoder_enum; + radeon_encoder->encoder_id = (encoder_enum & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; radeon_encoder->devices = supported_device; radeon_encoder->rmx_type = RMX_OFF; radeon_encoder->underscan_type = UNDERSCAN_OFF; diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index b8149cb..0b83970 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -1345,7 +1345,7 @@ static struct radeon_encoder_ext_tmds *radeon_legacy_get_ext_tmds_info(struct ra } void -radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t supported_device) +radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t supported_device) { struct radeon_device *rdev = dev->dev_private; struct drm_encoder *encoder; @@ -1354,7 +1354,7 @@ radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t /* see if we already added it */ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { radeon_encoder = to_radeon_encoder(encoder); - if (radeon_encoder->encoder_id == encoder_id) { + if (radeon_encoder->encoder_enum == encoder_enum) { radeon_encoder->devices |= supported_device; return; } @@ -1374,7 +1374,8 @@ radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t radeon_encoder->enc_priv = NULL; - radeon_encoder->encoder_id = encoder_id; + radeon_encoder->encoder_enum = encoder_enum; + radeon_encoder->encoder_id = (encoder_enum & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; radeon_encoder->devices = supported_device; radeon_encoder->rmx_type = RMX_OFF; diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 5bbc086..8f93e2b 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -342,6 +342,7 @@ struct radeon_atom_ss { }; struct radeon_encoder_atom_dig { + bool linkb; /* atom dig */ bool coherent_mode; int dig_encoder; /* -1 disabled, 0 DIGA, 1 DIGB */ @@ -360,6 +361,7 @@ struct radeon_encoder_atom_dac { struct radeon_encoder { struct drm_encoder base; + uint32_t encoder_enum; uint32_t encoder_id; uint32_t devices; uint32_t active_device; @@ -378,7 +380,6 @@ struct radeon_encoder { struct radeon_connector_atom_dig { uint32_t igp_lane_info; - bool linkb; /* displayport */ struct radeon_i2c_chan *dp_i2c_bus; u8 dpcd[8]; -- cgit v0.10.2 From e13b2ac1c46b9194ea9f44904760d3d49669529b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 12 Aug 2010 18:58:46 -0400 Subject: drm/radeon/kms: DCE3/4 transmitter fixes - INIT action takes the actual connector type id, not the enum id - some evergreen cards have the ENABLE_OUTPUT/DISABLE_OUTPUT actions Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 404320f..780bd30 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -843,7 +843,8 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t args.v1.ucAction = action; if (action == ATOM_TRANSMITTER_ACTION_INIT) { - args.v1.usInitInfo = radeon_connector->connector_object_id; + args.v1.usInitInfo = + (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { args.v1.asMode.ucLaneSel = lane_num; args.v1.asMode.ucLaneSet = lane_set; @@ -1072,8 +1073,7 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) if (is_dig) { switch (mode) { case DRM_MODE_DPMS_ON: - if (!ASIC_IS_DCE4(rdev)) - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0); + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0); if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) { struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); @@ -1085,8 +1085,7 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: - if (!ASIC_IS_DCE4(rdev)) - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0); + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0); if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) { if (ASIC_IS_DCE4(rdev)) atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF); -- cgit v0.10.2 From 4aab97e818c255a1bc25bb981f121a7992c6b290 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 12 Aug 2010 18:58:48 -0400 Subject: drm/radeon/kms/atom: clean up dig atom handling This allows the tables to be run in some additional cases where the connector info isn't necessary. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 780bd30..3d38cba 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -228,32 +228,6 @@ radeon_get_connector_for_encoder(struct drm_encoder *encoder) return NULL; } -static struct radeon_connector_atom_dig * -radeon_get_atom_connector_priv_from_encoder(struct drm_encoder *encoder) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct drm_connector *connector; - struct radeon_connector *radeon_connector; - struct radeon_connector_atom_dig *dig_connector; - - if (!rdev->is_atom_bios) - return NULL; - - connector = radeon_get_connector_for_encoder(encoder); - if (!connector) - return NULL; - - radeon_connector = to_radeon_connector(connector); - - if (!radeon_connector->con_priv) - return NULL; - - dig_connector = radeon_connector->con_priv; - - return dig_connector; -} - void radeon_panel_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { @@ -512,14 +486,12 @@ atombios_digital_setup(struct drm_encoder *encoder, int action) struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - struct radeon_connector_atom_dig *dig_connector = - radeon_get_atom_connector_priv_from_encoder(encoder); union lvds_encoder_control args; int index = 0; int hdmi_detected = 0; uint8_t frev, crev; - if (!dig || !dig_connector) + if (!dig) return; if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) @@ -729,13 +701,24 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action) struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - struct radeon_connector_atom_dig *dig_connector = - radeon_get_atom_connector_priv_from_encoder(encoder); + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); union dig_encoder_control args; int index = 0; uint8_t frev, crev; + int dp_clock = 0; + int dp_lane_count = 0; + + if (connector) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *dig_connector = + radeon_connector->con_priv; + + dp_clock = dig_connector->dp_clock; + dp_lane_count = dig_connector->dp_lane_count; + } - if (!dig || !dig_connector) + /* no dig encoder assigned */ + if (dig->dig_encoder == -1) return; memset(&args, 0, sizeof(args)); @@ -757,9 +740,9 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action) args.v1.ucEncoderMode = atombios_get_encoder_mode(encoder); if (args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) { - if (dig_connector->dp_clock == 270000) + if (dp_clock == 270000) args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; - args.v1.ucLaneNum = dig_connector->dp_lane_count; + args.v1.ucLaneNum = dp_lane_count; } else if (radeon_encoder->pixel_clock > 165000) args.v1.ucLaneNum = 8; else @@ -804,38 +787,47 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - struct radeon_connector_atom_dig *dig_connector = - radeon_get_atom_connector_priv_from_encoder(encoder); - struct drm_connector *connector; - struct radeon_connector *radeon_connector; + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); union dig_transmitter_control args; int index = 0; uint8_t frev, crev; bool is_dp = false; int pll_id = 0; + int dp_clock = 0; + int dp_lane_count = 0; + int connector_object_id = 0; + int igp_lane_info = 0; + + if (connector) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *dig_connector = + radeon_connector->con_priv; + + dp_clock = dig_connector->dp_clock; + dp_lane_count = dig_connector->dp_lane_count; + connector_object_id = + (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; + igp_lane_info = dig_connector->igp_lane_info; + } - if (!dig || !dig_connector) + /* no dig encoder assigned */ + if (dig->dig_encoder == -1) return; - connector = radeon_get_connector_for_encoder(encoder); - radeon_connector = to_radeon_connector(connector); - if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) is_dp = true; memset(&args, 0, sizeof(args)); - if (ASIC_IS_DCE32(rdev) || ASIC_IS_DCE4(rdev)) + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); - else { - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - index = GetIndexIntoMasterTable(COMMAND, DIG1TransmitterControl); - break; - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - index = GetIndexIntoMasterTable(COMMAND, DIG2TransmitterControl); - break; - } + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + index = GetIndexIntoMasterTable(COMMAND, LVTMATransmitterControl); + break; } if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) @@ -843,15 +835,14 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t args.v1.ucAction = action; if (action == ATOM_TRANSMITTER_ACTION_INIT) { - args.v1.usInitInfo = - (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; + args.v1.usInitInfo = connector_object_id; } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { args.v1.asMode.ucLaneSel = lane_num; args.v1.asMode.ucLaneSet = lane_set; } else { if (is_dp) args.v1.usPixelClock = - cpu_to_le16(dig_connector->dp_clock / 10); + cpu_to_le16(dp_clock / 10); else if (radeon_encoder->pixel_clock > 165000) args.v1.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); else @@ -859,7 +850,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t } if (ASIC_IS_DCE4(rdev)) { if (is_dp) - args.v3.ucLaneNum = dig_connector->dp_lane_count; + args.v3.ucLaneNum = dp_lane_count; else if (radeon_encoder->pixel_clock > 165000) args.v3.ucLaneNum = 8; else @@ -939,18 +930,18 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t if ((rdev->flags & RADEON_IS_IGP) && (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY)) { if (is_dp || (radeon_encoder->pixel_clock <= 165000)) { - if (dig_connector->igp_lane_info & 0x1) + if (igp_lane_info & 0x1) args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3; - else if (dig_connector->igp_lane_info & 0x2) + else if (igp_lane_info & 0x2) args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_4_7; - else if (dig_connector->igp_lane_info & 0x4) + else if (igp_lane_info & 0x4) args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_11; - else if (dig_connector->igp_lane_info & 0x8) + else if (igp_lane_info & 0x8) args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15; } else { - if (dig_connector->igp_lane_info & 0x3) + if (igp_lane_info & 0x3) args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7; - else if (dig_connector->igp_lane_info & 0xc) + else if (igp_lane_info & 0xc) args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15; } } -- cgit v0.10.2 From 4e186b2d6c878793587c35d7f06c94565d76e9b8 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 13 Aug 2010 10:53:35 -0400 Subject: drm/radeon/kms/pm: bail early if nothing's changing If we aren't changing the power state, no need to take locks and schedule fences, etc. There seem to be lock ordering issues in the CP and fence code in some cases; see bug 29140 below. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=29140 Possibly also: https://bugzilla.kernel.org/show_bug.cgi?id=16581 Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 58038f5c..477ba67 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -226,6 +226,11 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev) { int i; + /* no need to take locks, etc. if nothing's going to change */ + if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) && + (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index)) + return; + mutex_lock(&rdev->ddev->struct_mutex); mutex_lock(&rdev->vram_mutex); mutex_lock(&rdev->cp.mutex); -- cgit v0.10.2 From 5786e2c5a3f519647c50bbc276e45d36a704415a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 19 Aug 2010 11:19:31 -0400 Subject: drm/radeon/kms/DCE3+: switch pads to ddc mode when going i2c The pins for ddc and aux are shared so you need to switch the mode when doing ddc. The ProcessAuxChannel table already sets the pin mode to DP. This should fix unreliable ddc issues on DP ports using non-DP monitors. Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index bfd2ce5..0416804 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -99,6 +99,13 @@ static void radeon_i2c_do_lock(struct radeon_i2c_chan *i2c, int lock_state) } } + /* switch the pads to ddc mode */ + if (ASIC_IS_DCE3(rdev) && rec->hw_capable) { + temp = RREG32(rec->mask_clk_reg); + temp &= ~(1 << 16); + WREG32(rec->mask_clk_reg, temp); + } + /* clear the output pin values */ temp = RREG32(rec->a_clk_reg) & ~rec->a_clk_mask; WREG32(rec->a_clk_reg, temp); -- cgit v0.10.2 From 9c1ac0c6b97c6322c23cf3356028c28029c3b117 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 19 Aug 2010 14:28:33 -0400 Subject: drm/radeon/kms: add missing asic callback assignment for evergreen Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 646f96f..a21bf88 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -733,6 +733,7 @@ static struct radeon_asic evergreen_asic = { .set_engine_clock = &radeon_atom_set_engine_clock, .get_memory_clock = &radeon_atom_get_memory_clock, .set_memory_clock = &radeon_atom_set_memory_clock, + .get_pcie_lanes = NULL, .set_pcie_lanes = NULL, .set_clock_gating = NULL, .set_surface_reg = r600_set_surface_reg, -- cgit v0.10.2 From 6f50eae75b13e037e11f49128ea44a1a9a9535cb Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 19 Aug 2010 17:29:03 -0400 Subject: drm/radeon/kms: rework radeon_dp_detect() logic If the connector is eDP, it can only be DP, not TMDS. Always set the detected sink type. If the sink is detected as non-DP, but there is no EDID, you can still manually force the port on. If the sink type is DP and there's no DPCD, there's no way to force the monitor on since you need both ends to train the link. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 20c353c..31a09cd 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -977,24 +977,25 @@ static enum drm_connector_status radeon_dp_detect(struct drm_connector *connecto struct radeon_connector *radeon_connector = to_radeon_connector(connector); enum drm_connector_status ret = connector_status_disconnected; struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; - u8 sink_type; if (radeon_connector->edid) { kfree(radeon_connector->edid); radeon_connector->edid = NULL; } - sink_type = radeon_dp_getsinktype(radeon_connector); - if ((sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || - (sink_type == CONNECTOR_OBJECT_ID_eDP)) { - if (radeon_dp_getdpcd(radeon_connector)) { - radeon_dig_connector->dp_sink_type = sink_type; + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { + /* eDP is always DP */ + radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT; + if (radeon_dp_getdpcd(radeon_connector)) ret = connector_status_connected; - } } else { - if (radeon_ddc_probe(radeon_connector)) { - radeon_dig_connector->dp_sink_type = sink_type; - ret = connector_status_connected; + radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector); + if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) { + if (radeon_dp_getdpcd(radeon_connector)) + ret = connector_status_connected; + } else { + if (radeon_ddc_probe(radeon_connector)) + ret = connector_status_connected; } } -- cgit v0.10.2 From 19833b5dffe2f2e92a1b377f9aae9d5f32239512 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Thu, 19 Aug 2010 15:48:30 -0700 Subject: e1000e: disable ASPM L1 on 82573 On the e1000-devel mailing list, Nils Faerber reported latency issues with the 82573 LOM on a ThinkPad X60. It was found to be caused by ASPM L1; disabling it resolves the latency. The issue is present in kernels back to 2.6.34 and possibly 2.6.33. Reported-by: Nils Faerber Signed-off-by: Bruce Allan Cc: stable@kernel.org Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index a4a0d2b..f844e6c 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -1833,6 +1833,7 @@ struct e1000_info e1000_82573_info = { | FLAG_HAS_SMART_POWER_DOWN | FLAG_HAS_AMT | FLAG_HAS_SWSM_ON_LOAD, + .flags2 = FLAG2_DISABLE_ASPM_L1, .pba = 20, .max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN, .get_variants = e1000_get_variants_82571, -- cgit v0.10.2 From 161c48100236916e98d33a9c8b5fc8eae6decd15 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 19 Aug 2010 11:39:57 +0200 Subject: drm: fix end of loop test "agpmem" is never NULL here because it is the list cursor of a list_for_each_entry() list. Signed-off-by: Dan Carpenter Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c index 3778360..fda6746 100644 --- a/drivers/gpu/drm/drm_vm.c +++ b/drivers/gpu/drm/drm_vm.c @@ -138,7 +138,7 @@ static int drm_do_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) break; } - if (!agpmem) + if (&agpmem->head == &dev->agp->memory) goto vm_fault_error; /* -- cgit v0.10.2 From 09f0c489fa115a8b88a2da3edd0f3de00c8c7e2e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 19 Aug 2010 11:46:29 +0200 Subject: drm: move dereference below check "fb_helper_conn" is dereferenced before the check for NULL. It's never actually NULL here, so this is mostly to keep the static checkers happy. Signed-off-by: Dan Carpenter Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 7196620..cef8d8d 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -94,10 +94,11 @@ static bool drm_fb_helper_connector_parse_command_line(struct drm_fb_helper_conn int i; enum drm_connector_force force = DRM_FORCE_UNSPECIFIED; struct drm_fb_helper_cmdline_mode *cmdline_mode; - struct drm_connector *connector = fb_helper_conn->connector; + struct drm_connector *connector; if (!fb_helper_conn) return false; + connector = fb_helper_conn->connector; cmdline_mode = &fb_helper_conn->cmdline_mode; if (!mode_option) -- cgit v0.10.2 From 1aef70ef125165e0114a8e475636eff242a52030 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Thu, 19 Aug 2010 15:48:52 -0700 Subject: e1000e: don't check for alternate MAC addr on parts that don't support it From: Bruce Allan The alternate MAC address feature is only supported by 80003ES2LAN and 82571 LOMs as well as a couple 82571 mezzanine cards. Checking for an alternate MAC address on other parts can fail leading to the driver not able to load. This patch limits the check for an alternate MAC address to be done only for parts that support the feature. This issue has been around since support for the feature was introduced to the e1000e driver in 2.6.34. Signed-off-by: Bruce Allan Reported-by: Fabio Varesano Cc: stable@kernel.org Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index f844e6c..d3d4a57 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -936,12 +936,14 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw) ew32(IMC, 0xffffffff); icr = er32(ICR); - /* Install any alternate MAC address into RAR0 */ - ret_val = e1000_check_alt_mac_addr_generic(hw); - if (ret_val) - return ret_val; + if (hw->mac.type == e1000_82571) { + /* Install any alternate MAC address into RAR0 */ + ret_val = e1000_check_alt_mac_addr_generic(hw); + if (ret_val) + return ret_val; - e1000e_set_laa_state_82571(hw, true); + e1000e_set_laa_state_82571(hw, true); + } /* Reinitialize the 82571 serdes link state machine */ if (hw->phy.media_type == e1000_media_type_internal_serdes) @@ -1618,14 +1620,16 @@ static s32 e1000_read_mac_addr_82571(struct e1000_hw *hw) { s32 ret_val = 0; - /* - * If there's an alternate MAC address place it in RAR0 - * so that it will override the Si installed default perm - * address. - */ - ret_val = e1000_check_alt_mac_addr_generic(hw); - if (ret_val) - goto out; + if (hw->mac.type == e1000_82571) { + /* + * If there's an alternate MAC address place it in RAR0 + * so that it will override the Si installed default perm + * address. + */ + ret_val = e1000_check_alt_mac_addr_generic(hw); + if (ret_val) + goto out; + } ret_val = e1000_read_mac_addr_generic(hw); diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h index 307a72f4..93b3bed 100644 --- a/drivers/net/e1000e/defines.h +++ b/drivers/net/e1000e/defines.h @@ -621,6 +621,7 @@ #define E1000_FLASH_UPDATES 2000 /* NVM Word Offsets */ +#define NVM_COMPAT 0x0003 #define NVM_ID_LED_SETTINGS 0x0004 #define NVM_INIT_CONTROL2_REG 0x000F #define NVM_INIT_CONTROL3_PORT_B 0x0014 @@ -643,6 +644,9 @@ /* Mask bits for fields in Word 0x1a of the NVM */ #define NVM_WORD1A_ASPM_MASK 0x000C +/* Mask bits for fields in Word 0x03 of the EEPROM */ +#define NVM_COMPAT_LOM 0x0800 + /* For checksumming, the sum of all words in the NVM should equal 0xBABA. */ #define NVM_SUM 0xBABA diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c index df4a279..0fd4eb5 100644 --- a/drivers/net/e1000e/lib.c +++ b/drivers/net/e1000e/lib.c @@ -183,6 +183,16 @@ s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw) u16 offset, nvm_alt_mac_addr_offset, nvm_data; u8 alt_mac_addr[ETH_ALEN]; + ret_val = e1000_read_nvm(hw, NVM_COMPAT, 1, &nvm_data); + if (ret_val) + goto out; + + /* Check for LOM (vs. NIC) or one of two valid mezzanine cards */ + if (!((nvm_data & NVM_COMPAT_LOM) || + (hw->adapter->pdev->device == E1000_DEV_ID_82571EB_SERDES_DUAL) || + (hw->adapter->pdev->device == E1000_DEV_ID_82571EB_SERDES_QUAD))) + goto out; + ret_val = e1000_read_nvm(hw, NVM_ALT_MAC_ADDR_PTR, 1, &nvm_alt_mac_addr_offset); if (ret_val) { -- cgit v0.10.2 From e57415d85f72e36029b75fdb556c95fb5346b692 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 18 Aug 2010 13:34:11 -0400 Subject: drm/radeon/kms: fix agp mode setup on cards that use pcie bridges Asics that use an AGP to PCIE bridge don't have the AGP_STATUS register so just use whatever mode the host side setup. Signed-off-by: Alex Deucher Cc: Jerome Glisse Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_agp.c b/drivers/gpu/drm/radeon/radeon_agp.c index f40dfb7..bd2f33e 100644 --- a/drivers/gpu/drm/radeon/radeon_agp.c +++ b/drivers/gpu/drm/radeon/radeon_agp.c @@ -156,7 +156,13 @@ int radeon_agp_init(struct radeon_device *rdev) } mode.mode = info.mode; - agp_status = (RREG32(RADEON_AGP_STATUS) | RADEON_AGPv3_MODE) & mode.mode; + /* chips with the agp to pcie bridge don't have the AGP_STATUS register + * Just use the whatever mode the host sets up. + */ + if (rdev->family <= CHIP_RV350) + agp_status = (RREG32(RADEON_AGP_STATUS) | RADEON_AGPv3_MODE) & mode.mode; + else + agp_status = mode.mode; is_v3 = !!(agp_status & RADEON_AGPv3_MODE); if (is_v3) { -- cgit v0.10.2 From da7be684c55dbaeebfc1a048d5faf52d52cb3c1f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 12 Aug 2010 18:05:34 -0400 Subject: drm/radeon/kms: don't enable MSIs on AGP boards Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=29327 Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 059bfa4..a108c7e 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -121,11 +121,12 @@ int radeon_irq_kms_init(struct radeon_device *rdev) * chips. Disable MSI on them for now. */ if ((rdev->family >= CHIP_RV380) && - (!(rdev->flags & RADEON_IS_IGP))) { + (!(rdev->flags & RADEON_IS_IGP)) && + (!(rdev->flags & RADEON_IS_AGP))) { int ret = pci_enable_msi(rdev->pdev); if (!ret) { rdev->msi_enabled = 1; - DRM_INFO("radeon: using MSI.\n"); + dev_info(rdev->dev, "radeon: using MSI.\n"); } } rdev->irq.installed = true; -- cgit v0.10.2 From b824b364d9ee001fc8c6bb71cc49f19bf740dd99 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 12 Aug 2010 08:25:47 -0400 Subject: drm/radeon/kms: add back missing break in info ioctl This seems to have gotten lost in the hyper-z merge. Noticed by legume on IRC. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 27435db..5eee3c4 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -161,6 +161,7 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) DRM_DEBUG_KMS("tiling config is r6xx+ only!\n"); return -EINVAL; } + break; case RADEON_INFO_WANT_HYPERZ: /* The "value" here is both an input and output parameter. * If the input value is 1, filp requests hyper-z access. -- cgit v0.10.2 From d033af87e2a215a57ac2bbc47e0d7a544f2afcc4 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 20 Aug 2010 01:09:22 -0400 Subject: drm/radeon/kms: set encoder type to DVI for HDMI on evergreen Fixes the pink line that shows up with some hdmi monitors. This will need to be revisited when audio support is added. Fixes: http://bugs.freedesktop.org/show_bug.cgi?id=27452 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 3d38cba..2c293e8 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -595,6 +595,8 @@ atombios_digital_setup(struct drm_encoder *encoder, int action) int atombios_get_encoder_mode(struct drm_encoder *encoder) { + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; struct drm_connector *connector; struct radeon_connector *radeon_connector; struct radeon_connector_atom_dig *dig_connector; @@ -608,9 +610,13 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) switch (connector->connector_type) { case DRM_MODE_CONNECTOR_DVII: case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */ - if (drm_detect_hdmi_monitor(radeon_connector->edid)) - return ATOM_ENCODER_MODE_HDMI; - else if (radeon_connector->use_digital) + if (drm_detect_hdmi_monitor(radeon_connector->edid)) { + /* fix me */ + if (ASIC_IS_DCE4(rdev)) + return ATOM_ENCODER_MODE_DVI; + else + return ATOM_ENCODER_MODE_HDMI; + } else if (radeon_connector->use_digital) return ATOM_ENCODER_MODE_DVI; else return ATOM_ENCODER_MODE_CRT; @@ -618,9 +624,13 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) case DRM_MODE_CONNECTOR_DVID: case DRM_MODE_CONNECTOR_HDMIA: default: - if (drm_detect_hdmi_monitor(radeon_connector->edid)) - return ATOM_ENCODER_MODE_HDMI; - else + if (drm_detect_hdmi_monitor(radeon_connector->edid)) { + /* fix me */ + if (ASIC_IS_DCE4(rdev)) + return ATOM_ENCODER_MODE_DVI; + else + return ATOM_ENCODER_MODE_HDMI; + } else return ATOM_ENCODER_MODE_DVI; break; case DRM_MODE_CONNECTOR_LVDS: @@ -632,9 +642,13 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) return ATOM_ENCODER_MODE_DP; - else if (drm_detect_hdmi_monitor(radeon_connector->edid)) - return ATOM_ENCODER_MODE_HDMI; - else + else if (drm_detect_hdmi_monitor(radeon_connector->edid)) { + /* fix me */ + if (ASIC_IS_DCE4(rdev)) + return ATOM_ENCODER_MODE_DVI; + else + return ATOM_ENCODER_MODE_HDMI; + } else return ATOM_ENCODER_MODE_DVI; break; case DRM_MODE_CONNECTOR_DVIA: -- cgit v0.10.2 From 4f34760787c3751a3146f0eecdc79c3e97b94962 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 20 Aug 2010 09:41:59 +0200 Subject: ALSA: hda - Fix conflict of sticky PCM parameter in HDMI codecs Intel and Nvidia HDMI codec drivers have own implementations of sticky PCM parameters. Now HD-audio core part already has it, thus both setups conflict. The fix is simply remove the part in patch_intelhdmi.c and patch_nvhdmi.c and simply call snd_hda_codec_setup_stream() as usual. Reported-and-tested-by: Stephen Warren Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 2bc0f07..afd6022 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -707,8 +707,6 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag, int format) { struct hdmi_spec *spec = codec->spec; - int tag; - int fmt; int pinctl; int new_pinctl = 0; int i; @@ -745,24 +743,7 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid, return -EINVAL; } - tag = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0) >> 4; - fmt = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_STREAM_FORMAT, 0); - - snd_printdd("hdmi_setup_stream: " - "NID=0x%x, %sstream=0x%x, %sformat=0x%x\n", - nid, - tag == stream_tag ? "" : "new-", - stream_tag, - fmt == format ? "" : "new-", - format); - - if (tag != stream_tag) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_CHANNEL_STREAMID, - stream_tag << 4); - if (fmt != format) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_STREAM_FORMAT, format); + snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); return 0; } diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index d382d3c..36a9b83 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -69,20 +69,12 @@ static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format); } -static int intel_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - return 0; -} - static struct hda_pcm_stream intel_hdmi_pcm_playback = { .substreams = 1, .channels_min = 2, .ops = { .open = hdmi_pcm_open, .prepare = intel_hdmi_playback_pcm_prepare, - .cleanup = intel_hdmi_playback_pcm_cleanup, }, }; diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index f636870..69b950d 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c @@ -326,13 +326,6 @@ static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo, return 0; } -static int nvhdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - return 0; -} - static int nvhdmi_dig_playback_pcm_prepare_2ch(struct hda_pcm_stream *hinfo, struct hda_codec *codec, unsigned int stream_tag, @@ -350,7 +343,6 @@ static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch_89 = { .ops = { .open = hdmi_pcm_open, .prepare = nvhdmi_dig_playback_pcm_prepare_8ch_89, - .cleanup = nvhdmi_playback_pcm_cleanup, }, }; -- cgit v0.10.2 From 3f50ac6a0ec80a83a1a033fe5004fb319ad72db7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 20 Aug 2010 09:44:36 +0200 Subject: ALSA: hda - Fix stream and channel-ids codec-bus wide The new sticky PCM parameter introduced the delayed clean-ups of stream- and channel-id tags. In the current implementation, this check (adding dirty flag) and actual clean-ups are done only for the codec chip. However, with HD-audio architecture, multiple codecs can be on a single bus, and the controller assign stream- and channel-ids in the bus-wide. In this patch, the stream-id and channel-id are checked over all codecs connected to the corresponding bus. Together with it, the mutex is moved to struct hda_bus, as this becomes also bus-wide. Reported-and-tested-by: Stephen Warren Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index dd8fb86..3827092 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -589,6 +589,7 @@ int /*__devinit*/ snd_hda_bus_new(struct snd_card *card, bus->ops = temp->ops; mutex_init(&bus->cmd_mutex); + mutex_init(&bus->prepare_mutex); INIT_LIST_HEAD(&bus->codec_list); snprintf(bus->workq_name, sizeof(bus->workq_name), @@ -1068,7 +1069,6 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, codec->addr = codec_addr; mutex_init(&codec->spdif_mutex); mutex_init(&codec->control_mutex); - mutex_init(&codec->prepare_mutex); init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32); @@ -1213,6 +1213,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag, int channel_id, int format) { + struct hda_codec *c; struct hda_cvt_setup *p; unsigned int oldval, newval; int i; @@ -1253,10 +1254,12 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, p->dirty = 0; /* make other inactive cvts with the same stream-tag dirty */ - for (i = 0; i < codec->cvt_setups.used; i++) { - p = snd_array_elem(&codec->cvt_setups, i); - if (!p->active && p->stream_tag == stream_tag) - p->dirty = 1; + list_for_each_entry(c, &codec->bus->codec_list, list) { + for (i = 0; i < c->cvt_setups.used; i++) { + p = snd_array_elem(&c->cvt_setups, i); + if (!p->active && p->stream_tag == stream_tag) + p->dirty = 1; + } } } EXPORT_SYMBOL_HDA(snd_hda_codec_setup_stream); @@ -1306,12 +1309,16 @@ static void really_cleanup_stream(struct hda_codec *codec, /* clean up the all conflicting obsolete streams */ static void purify_inactive_streams(struct hda_codec *codec) { + struct hda_codec *c; int i; - for (i = 0; i < codec->cvt_setups.used; i++) { - struct hda_cvt_setup *p = snd_array_elem(&codec->cvt_setups, i); - if (p->dirty) - really_cleanup_stream(codec, p); + list_for_each_entry(c, &codec->bus->codec_list, list) { + for (i = 0; i < c->cvt_setups.used; i++) { + struct hda_cvt_setup *p; + p = snd_array_elem(&c->cvt_setups, i); + if (p->dirty) + really_cleanup_stream(c, p); + } } } @@ -3502,11 +3509,11 @@ int snd_hda_codec_prepare(struct hda_codec *codec, struct snd_pcm_substream *substream) { int ret; - mutex_lock(&codec->prepare_mutex); + mutex_lock(&codec->bus->prepare_mutex); ret = hinfo->ops.prepare(hinfo, codec, stream, format, substream); if (ret >= 0) purify_inactive_streams(codec); - mutex_unlock(&codec->prepare_mutex); + mutex_unlock(&codec->bus->prepare_mutex); return ret; } EXPORT_SYMBOL_HDA(snd_hda_codec_prepare); @@ -3515,9 +3522,9 @@ void snd_hda_codec_cleanup(struct hda_codec *codec, struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { - mutex_lock(&codec->prepare_mutex); + mutex_lock(&codec->bus->prepare_mutex); hinfo->ops.cleanup(hinfo, codec, substream); - mutex_unlock(&codec->prepare_mutex); + mutex_unlock(&codec->bus->prepare_mutex); } EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 4303353..62c7022 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -648,6 +648,7 @@ struct hda_bus { struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1]; struct mutex cmd_mutex; + struct mutex prepare_mutex; /* unsolicited event queue */ struct hda_bus_unsolicited *unsol; @@ -826,7 +827,6 @@ struct hda_codec { struct mutex spdif_mutex; struct mutex control_mutex; - struct mutex prepare_mutex; unsigned int spdif_status; /* IEC958 status bits */ unsigned short spdif_ctls; /* SPDIF control bits */ unsigned int spdif_in_enable; /* SPDIF input enable? */ -- cgit v0.10.2 From 05e407603e527f9d808dd3866d3a17c2ce4dfcc5 Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Fri, 20 Aug 2010 00:46:16 +0200 Subject: x86, apic: Fix apic=debug boot crash Fix a boot crash when apic=debug is used and the APIC is not properly initialized. This issue appears during Xen Dom0 kernel boot but the fix is generic and the crash could occur on real hardware as well. Signed-off-by: Daniel Kiper Cc: xen-devel@lists.xensource.com Cc: konrad.wilk@oracle.com Cc: jeremy@goop.org Cc: # .35.x, .34.x, .33.x, .32.x LKML-Reference: <20100819224616.GB9967@router-fw-old.local.net-space.pl> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 4dc0084..f1efeba 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -1728,6 +1728,8 @@ __apicdebuginit(void) print_IO_APIC(void) struct irq_pin_list *entry; cfg = desc->chip_data; + if (!cfg) + continue; entry = cfg->irq_2_pin; if (!entry) continue; -- cgit v0.10.2 From 7b8ea53d7f1865cd8f05dfb8f706a4ff5a72abcf Mon Sep 17 00:00:00 2001 From: Amerigo Wang Date: Fri, 20 Aug 2010 05:36:06 -0400 Subject: makefile: not need to regenerate kernel.release file when make kernelrelease Brice reported that 'kernelrelease' has a dependence on include/config/kernel.release, causes this file to be regenerated every time when invoke it. It doesn't have to. Reported-by: Brice Goglin Tested-by: Brice Goglin Signed-off-by: WANG Cong Signed-off-by: Michal Marek diff --git a/Makefile b/Makefile index f3bdff8..25da252 100644 --- a/Makefile +++ b/Makefile @@ -1408,8 +1408,8 @@ checkstack: $(OBJDUMP) -d vmlinux $$(find . -name '*.ko') | \ $(PERL) $(src)/scripts/checkstack.pl $(CHECKSTACK_ARCH) -kernelrelease: include/config/kernel.release - @echo $(KERNELRELEASE) +kernelrelease: + @echo "$(KERNELVERSION)$$($(CONFIG_SHELL) $(srctree)/scripts/setlocalversion $(srctree))" kernelversion: @echo $(KERNELVERSION) -- cgit v0.10.2 From c81476df1b4241aefba4ff83a7701b3a926bd7ce Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Thu, 19 Aug 2010 14:13:25 -0700 Subject: matroxfb: fix incorrect use of memcpy_toio() Screen is completely corrupted since 2.6.34. Bisection revealed that it's caused by commit 6175ddf06b61720 ("x86: Clean up mem*io functions."). H. Peter Anvin explained that memcpy_toio() does not copy data in 32bit chunks anymore on x86. Signed-off-by: Ondrej Zary Cc: Brian Gerst Cc: H. Peter Anvin Cc: Petr Vandrovec Cc: Jean Delvare Cc: [2.6.34.x, 2.6.35.x] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h index f3a4e15..f96a471 100644 --- a/drivers/video/matrox/matroxfb_base.h +++ b/drivers/video/matrox/matroxfb_base.h @@ -151,13 +151,13 @@ static inline void mga_writel(vaddr_t va, unsigned int offs, u_int32_t value) { static inline void mga_memcpy_toio(vaddr_t va, const void* src, int len) { #if defined(__alpha__) || defined(__i386__) || defined(__x86_64__) /* - * memcpy_toio works for us if: + * iowrite32_rep works for us if: * (1) Copies data as 32bit quantities, not byte after byte, * (2) Performs LE ordered stores, and * (3) It copes with unaligned source (destination is guaranteed to be page * aligned and length is guaranteed to be multiple of 4). */ - memcpy_toio(va.vaddr, src, len); + iowrite32_rep(va.vaddr, src, len >> 2); #else u_int32_t __iomem* addr = va.vaddr; -- cgit v0.10.2 From b35de43b31040828f83046f40fd34ba33146409d Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Thu, 19 Aug 2010 14:13:27 -0700 Subject: kfifo: implement missing __kfifo_skip_r() kfifo_skip() is currently broken, due to the missing of the internal helper function. Add it. Signed-off-by: Andrea Righi Cc: Greg KH Acked-by: Stefani Seibold Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/kfifo.h b/include/linux/kfifo.h index 311f875..4aa95f2 100644 --- a/include/linux/kfifo.h +++ b/include/linux/kfifo.h @@ -836,6 +836,8 @@ extern void __kfifo_dma_out_finish_r(struct __kfifo *fifo, size_t recsize); extern unsigned int __kfifo_len_r(struct __kfifo *fifo, size_t recsize); +extern void __kfifo_skip_r(struct __kfifo *fifo, size_t recsize); + extern unsigned int __kfifo_out_peek_r(struct __kfifo *fifo, void *buf, unsigned int len, size_t recsize); diff --git a/kernel/kfifo.c b/kernel/kfifo.c index 4502604..6b5580c 100644 --- a/kernel/kfifo.c +++ b/kernel/kfifo.c @@ -503,6 +503,15 @@ unsigned int __kfifo_out_r(struct __kfifo *fifo, void *buf, } EXPORT_SYMBOL(__kfifo_out_r); +void __kfifo_skip_r(struct __kfifo *fifo, size_t recsize) +{ + unsigned int n; + + n = __kfifo_peek_n(fifo, recsize); + fifo->out += n + recsize; +} +EXPORT_SYMBOL(__kfifo_skip_r); + int __kfifo_from_user_r(struct __kfifo *fifo, const void __user *from, unsigned long len, unsigned int *copied, size_t recsize) { -- cgit v0.10.2 From 5ddf83912c8b49a24ab0841f6d77f33781dcf10f Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Thu, 19 Aug 2010 14:13:28 -0700 Subject: kfifo: add kfifo_skip() testcase Add a testcase for kfifo_skip() to the byte stream fifo example. Signed-off-by: Andrea Righi Cc: Greg KH Acked-by: Stefani Seibold Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/samples/kfifo/bytestream-example.c b/samples/kfifo/bytestream-example.c index 642eef3..2e3a7a8 100644 --- a/samples/kfifo/bytestream-example.c +++ b/samples/kfifo/bytestream-example.c @@ -73,6 +73,10 @@ static int __init testfunc(void) ret = kfifo_in(&test, buf, ret); printk(KERN_INFO "ret: %d\n", ret); + /* skip first element of the fifo */ + printk(KERN_INFO "skip 1st element\n"); + kfifo_skip(&test); + /* put values into the fifo until is full */ for (i = 20; kfifo_put(&test, &i); i++) ; -- cgit v0.10.2 From 2aaf2092c168fc02df0645415f524b357ee7ec2e Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Thu, 19 Aug 2010 14:13:29 -0700 Subject: kfifo: add explicit error checking in byte stream example Provide a static array of expected items that kfifo should contain at the end of the test to validate it. Signed-off-by: Andrea Righi Cc: Stefani Seibold Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/samples/kfifo/bytestream-example.c b/samples/kfifo/bytestream-example.c index 2e3a7a8..a94e694 100644 --- a/samples/kfifo/bytestream-example.c +++ b/samples/kfifo/bytestream-example.c @@ -44,10 +44,17 @@ static struct kfifo test; static DECLARE_KFIFO(test, unsigned char, FIFO_SIZE); #endif +static unsigned char expected_result[FIFO_SIZE] = { + 3, 4, 5, 6, 7, 8, 9, 0, + 1, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, +}; + static int __init testfunc(void) { unsigned char buf[6]; - unsigned char i; + unsigned char i, j; unsigned int ret; printk(KERN_INFO "byte stream fifo test start\n"); @@ -83,10 +90,19 @@ static int __init testfunc(void) printk(KERN_INFO "queue len: %u\n", kfifo_len(&test)); - /* print out all values in the fifo */ - while (kfifo_get(&test, &i)) - printk("%d ", i); - printk("\n"); + /* check the correctness of all values in the fifo */ + j = 0; + while (kfifo_get(&test, &i)) { + if (i != expected_result[j++]) { + printk(KERN_WARNING "value mismatch: test failed\n"); + return -EIO; + } + } + if (j != ARRAY_SIZE(expected_result)) { + printk(KERN_WARNING "size mismatch: test failed\n"); + return -EIO; + } + printk(KERN_INFO "test passed\n"); return 0; } @@ -142,7 +158,12 @@ static int __init example_init(void) #else INIT_KFIFO(test); #endif - testfunc(); + if (testfunc() < 0) { +#ifdef DYNAMIC + kfifo_free(&test); +#endif + return -EIO; + } if (proc_create(PROC_FIFO, 0, NULL, &fifo_fops) == NULL) { #ifdef DYNAMIC -- cgit v0.10.2 From 7b34d5257a90c419d67c1c3b52f87a679845ef1e Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Thu, 19 Aug 2010 14:13:29 -0700 Subject: kfifo: fix kernel BUG in dma example The scatterlist is used uninitialized in kfifo_dma_in_prepare(). This triggers the following bug if CONFIG_DEBUG_SG=y: ------------[ cut here ]------------ kernel BUG at include/linux/scatterlist.h:65! invalid opcode: 0000 [#1] PREEMPT SMP ... Call Trace: [] setup_sgl+0x6b/0xe0 [] ? example_init+0x0/0x265 [dma_example] [] __kfifo_dma_in_prepare+0x21/0x30 [] example_init+0x124/0x265 [dma_example] [] ? trace_module_notify+0x25/0x370 [] ? free_pages_prepare+0x11e/0x1e0 [] ? get_parent_ip+0x11/0x50 [] ? trace_module_notify+0x25/0x370 [] ? trace_hardirqs_on+0xd/0x10 [] ? mutex_unlock+0xe/0x10 [] ? trace_module_notify+0x41/0x370 [] ? __blocking_notifier_call_chain+0x45/0x80 [] ? vfree+0x2a/0x30 [] ? up_read+0x23/0x40 [] ? __blocking_notifier_call_chain+0x65/0x80 [] do_one_initcall+0x43/0x180 [] sys_init_module+0xba/0x200 [] system_call_fastpath+0x16/0x1b RIP [] setup_sgl_buf+0x1a1/0x1b0 RSP ---[ end trace a72b979fd3c1d3a5 ]--- Add the proper initialization to avoid the bug. Signed-off-by: Andrea Righi Acked-by: Stefani Seibold Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/samples/kfifo/dma-example.c b/samples/kfifo/dma-example.c index b9482c2..03433ca 100644 --- a/samples/kfifo/dma-example.c +++ b/samples/kfifo/dma-example.c @@ -45,6 +45,7 @@ static int __init example_init(void) printk(KERN_INFO "queue len: %u\n", kfifo_len(&fifo)); + sg_init_table(sg, ARRAY_SIZE(sg)); ret = kfifo_dma_in_prepare(&fifo, sg, ARRAY_SIZE(sg), FIFO_SIZE); printk(KERN_INFO "DMA sgl entries: %d\n", ret); -- cgit v0.10.2 From d83a71c4219191a9a881318ae5ca9b39aa1d0540 Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Thu, 19 Aug 2010 14:13:30 -0700 Subject: kfifo: fix a memory leak in dma example We use a dynamically allocated kfifo in the dma example, so we need to free it when unloading the module. Signed-off-by: Andrea Righi Acked-by: Stefani Seibold Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/samples/kfifo/dma-example.c b/samples/kfifo/dma-example.c index 03433ca..3682278 100644 --- a/samples/kfifo/dma-example.c +++ b/samples/kfifo/dma-example.c @@ -105,9 +105,7 @@ static int __init example_init(void) static void __exit example_exit(void) { -#ifdef DYNAMIC - kfifo_free(&test); -#endif + kfifo_free(&fifo); } module_init(example_init); -- cgit v0.10.2 From a25effa4d265eb5028c7d4a92a0ddd9267c3c43d Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Thu, 19 Aug 2010 14:13:30 -0700 Subject: kfifo: add explicit error checking in all the examples Provide a check in all the kfifo examples to validate the correct execution of each testcase. Signed-off-by: Andrea Righi Acked-by: Stefani Seibold Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/samples/kfifo/bytestream-example.c b/samples/kfifo/bytestream-example.c index a94e694..178061e 100644 --- a/samples/kfifo/bytestream-example.c +++ b/samples/kfifo/bytestream-example.c @@ -44,7 +44,7 @@ static struct kfifo test; static DECLARE_KFIFO(test, unsigned char, FIFO_SIZE); #endif -static unsigned char expected_result[FIFO_SIZE] = { +static const unsigned char expected_result[FIFO_SIZE] = { 3, 4, 5, 6, 7, 8, 9, 0, 1, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, @@ -90,9 +90,14 @@ static int __init testfunc(void) printk(KERN_INFO "queue len: %u\n", kfifo_len(&test)); + /* show the first value without removing from the fifo */ + if (kfifo_peek(&test, &i)) + printk(KERN_INFO "%d\n", i); + /* check the correctness of all values in the fifo */ j = 0; while (kfifo_get(&test, &i)) { + printk(KERN_INFO "item = %d\n", i); if (i != expected_result[j++]) { printk(KERN_WARNING "value mismatch: test failed\n"); return -EIO; diff --git a/samples/kfifo/dma-example.c b/samples/kfifo/dma-example.c index 3682278..ee03a4f 100644 --- a/samples/kfifo/dma-example.c +++ b/samples/kfifo/dma-example.c @@ -29,8 +29,8 @@ static int __init example_init(void) printk(KERN_INFO "DMA fifo test start\n"); if (kfifo_alloc(&fifo, FIFO_SIZE, GFP_KERNEL)) { - printk(KERN_ERR "error kfifo_alloc\n"); - return 1; + printk(KERN_WARNING "error kfifo_alloc\n"); + return -ENOMEM; } printk(KERN_INFO "queue size: %u\n", kfifo_size(&fifo)); @@ -41,65 +41,93 @@ static int __init example_init(void) kfifo_put(&fifo, &i); /* kick away first byte */ - ret = kfifo_get(&fifo, &i); + kfifo_skip(&fifo); printk(KERN_INFO "queue len: %u\n", kfifo_len(&fifo)); + /* + * Configure the kfifo buffer to receive data from DMA input. + * + * .--------------------------------------. + * | 0 | 1 | 2 | ... | 12 | 13 | ... | 31 | + * |---|------------------|---------------| + * \_/ \________________/ \_____________/ + * \ \ \ + * \ \_allocated data \ + * \_*free space* \_*free space* + * + * We need two different SG entries: one for the free space area at the + * end of the kfifo buffer (19 bytes) and another for the first free + * byte at the beginning, after the kfifo_skip(). + */ sg_init_table(sg, ARRAY_SIZE(sg)); ret = kfifo_dma_in_prepare(&fifo, sg, ARRAY_SIZE(sg), FIFO_SIZE); printk(KERN_INFO "DMA sgl entries: %d\n", ret); + if (!ret) { + /* fifo is full and no sgl was created */ + printk(KERN_WARNING "error kfifo_dma_in_prepare\n"); + return -EIO; + } - /* if 0 was returned, fifo is full and no sgl was created */ - if (ret) { - printk(KERN_INFO "scatterlist for receive:\n"); - for (i = 0; i < ARRAY_SIZE(sg); i++) { - printk(KERN_INFO - "sg[%d] -> " - "page_link 0x%.8lx offset 0x%.8x length 0x%.8x\n", - i, sg[i].page_link, sg[i].offset, sg[i].length); + /* receive data */ + printk(KERN_INFO "scatterlist for receive:\n"); + for (i = 0; i < ARRAY_SIZE(sg); i++) { + printk(KERN_INFO + "sg[%d] -> " + "page_link 0x%.8lx offset 0x%.8x length 0x%.8x\n", + i, sg[i].page_link, sg[i].offset, sg[i].length); - if (sg_is_last(&sg[i])) - break; - } + if (sg_is_last(&sg[i])) + break; + } - /* but here your code to setup and exectute the dma operation */ - /* ... */ + /* put here your code to setup and exectute the dma operation */ + /* ... */ - /* example: zero bytes received */ - ret = 0; + /* example: zero bytes received */ + ret = 0; - /* finish the dma operation and update the received data */ - kfifo_dma_in_finish(&fifo, ret); - } + /* finish the dma operation and update the received data */ + kfifo_dma_in_finish(&fifo, ret); + /* Prepare to transmit data, example: 8 bytes */ ret = kfifo_dma_out_prepare(&fifo, sg, ARRAY_SIZE(sg), 8); printk(KERN_INFO "DMA sgl entries: %d\n", ret); + if (!ret) { + /* no data was available and no sgl was created */ + printk(KERN_WARNING "error kfifo_dma_out_prepare\n"); + return -EIO; + } - /* if 0 was returned, no data was available and no sgl was created */ - if (ret) { - printk(KERN_INFO "scatterlist for transmit:\n"); - for (i = 0; i < ARRAY_SIZE(sg); i++) { - printk(KERN_INFO - "sg[%d] -> " - "page_link 0x%.8lx offset 0x%.8x length 0x%.8x\n", - i, sg[i].page_link, sg[i].offset, sg[i].length); + printk(KERN_INFO "scatterlist for transmit:\n"); + for (i = 0; i < ARRAY_SIZE(sg); i++) { + printk(KERN_INFO + "sg[%d] -> " + "page_link 0x%.8lx offset 0x%.8x length 0x%.8x\n", + i, sg[i].page_link, sg[i].offset, sg[i].length); - if (sg_is_last(&sg[i])) - break; - } + if (sg_is_last(&sg[i])) + break; + } - /* but here your code to setup and exectute the dma operation */ - /* ... */ + /* put here your code to setup and exectute the dma operation */ + /* ... */ - /* example: 5 bytes transmitted */ - ret = 5; + /* example: 5 bytes transmitted */ + ret = 5; - /* finish the dma operation and update the transmitted data */ - kfifo_dma_out_finish(&fifo, ret); - } + /* finish the dma operation and update the transmitted data */ + kfifo_dma_out_finish(&fifo, ret); + ret = kfifo_len(&fifo); printk(KERN_INFO "queue len: %u\n", kfifo_len(&fifo)); + if (ret != 7) { + printk(KERN_WARNING "size mismatch: test failed"); + return -EIO; + } + printk(KERN_INFO "test passed\n"); + return 0; } diff --git a/samples/kfifo/inttype-example.c b/samples/kfifo/inttype-example.c index d6c5b7d..71b2aab 100644 --- a/samples/kfifo/inttype-example.c +++ b/samples/kfifo/inttype-example.c @@ -44,10 +44,17 @@ static DECLARE_KFIFO_PTR(test, int); static DEFINE_KFIFO(test, int, FIFO_SIZE); #endif +static const int expected_result[FIFO_SIZE] = { + 3, 4, 5, 6, 7, 8, 9, 0, + 1, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, +}; + static int __init testfunc(void) { int buf[6]; - int i; + int i, j; unsigned int ret; printk(KERN_INFO "int fifo test start\n"); @@ -66,8 +73,13 @@ static int __init testfunc(void) ret = kfifo_in(&test, buf, ret); printk(KERN_INFO "ret: %d\n", ret); - for (i = 20; i != 30; i++) - kfifo_put(&test, &i); + /* skip first element of the fifo */ + printk(KERN_INFO "skip 1st element\n"); + kfifo_skip(&test); + + /* put values into the fifo until is full */ + for (i = 20; kfifo_put(&test, &i); i++) + ; printk(KERN_INFO "queue len: %u\n", kfifo_len(&test)); @@ -75,10 +87,20 @@ static int __init testfunc(void) if (kfifo_peek(&test, &i)) printk(KERN_INFO "%d\n", i); - /* print out all values in the fifo */ - while (kfifo_get(&test, &i)) - printk("%d ", i); - printk("\n"); + /* check the correctness of all values in the fifo */ + j = 0; + while (kfifo_get(&test, &i)) { + printk(KERN_INFO "item = %d\n", i); + if (i != expected_result[j++]) { + printk(KERN_WARNING "value mismatch: test failed\n"); + return -EIO; + } + } + if (j != ARRAY_SIZE(expected_result)) { + printk(KERN_WARNING "size mismatch: test failed\n"); + return -EIO; + } + printk(KERN_INFO "test passed\n"); return 0; } @@ -132,7 +154,12 @@ static int __init example_init(void) return ret; } #endif - testfunc(); + if (testfunc() < 0) { +#ifdef DYNAMIC + kfifo_free(&test); +#endif + return -EIO; + } if (proc_create(PROC_FIFO, 0, NULL, &fifo_fops) == NULL) { #ifdef DYNAMIC diff --git a/samples/kfifo/record-example.c b/samples/kfifo/record-example.c index 32c6e0b..e68bd16 100644 --- a/samples/kfifo/record-example.c +++ b/samples/kfifo/record-example.c @@ -55,6 +55,19 @@ typedef STRUCT_KFIFO_REC_1(FIFO_SIZE) mytest; static mytest test; #endif +static const char *expected_result[] = { + "a", + "bb", + "ccc", + "dddd", + "eeeee", + "ffffff", + "ggggggg", + "hhhhhhhh", + "iiiiiiiii", + "jjjjjjjjjj", +}; + static int __init testfunc(void) { char buf[100]; @@ -75,6 +88,10 @@ static int __init testfunc(void) kfifo_in(&test, buf, i + 1); } + /* skip first element of the fifo */ + printk(KERN_INFO "skip 1st element\n"); + kfifo_skip(&test); + printk(KERN_INFO "fifo len: %u\n", kfifo_len(&test)); /* show the first record without removing from the fifo */ @@ -82,11 +99,22 @@ static int __init testfunc(void) if (ret) printk(KERN_INFO "%.*s\n", ret, buf); - /* print out all records in the fifo */ + /* check the correctness of all values in the fifo */ + i = 0; while (!kfifo_is_empty(&test)) { ret = kfifo_out(&test, buf, sizeof(buf)); - printk(KERN_INFO "%.*s\n", ret, buf); + buf[ret] = '\0'; + printk(KERN_INFO "item = %.*s\n", ret, buf); + if (strcmp(buf, expected_result[i++])) { + printk(KERN_WARNING "value mismatch: test failed\n"); + return -EIO; + } + } + if (i != ARRAY_SIZE(expected_result)) { + printk(KERN_WARNING "size mismatch: test failed\n"); + return -EIO; } + printk(KERN_INFO "test passed\n"); return 0; } @@ -142,7 +170,12 @@ static int __init example_init(void) #else INIT_KFIFO(test); #endif - testfunc(); + if (testfunc() < 0) { +#ifdef DYNAMIC + kfifo_free(&test); +#endif + return -EIO; + } if (proc_create(PROC_FIFO, 0, NULL, &fifo_fops) == NULL) { #ifdef DYNAMIC -- cgit v0.10.2 From f2e41e910320197d55b52e28d99a07130f2ae738 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 19 Aug 2010 14:13:31 -0700 Subject: revert "hwmon: f71882fg: add support for the Fintek F71808E" Revert commit 7721fea3d0fd93fb4d000eb737b444369358d6d3 ("hwmon: f71882fg: add support for the Fintek F71808E"). Hans said: : A second review after I've received a data sheet for this device from : Fintek has turned up a few bugs. : : Unfortunately Giel (nor I) have time to fix this in time for the 2.6.36 : cycle. Therefor I would like to see this patch reverted as not having any : support for the hwmon function of this superio chip is better then having : unreliable support. Cc: Giel van Schijndel Cc: Jean Delvare Cc: Hans de Goede Cc: Jonathan Cameron Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/hwmon/f71882fg b/Documentation/hwmon/f71882fg index 1a07fd6..a7952c2 100644 --- a/Documentation/hwmon/f71882fg +++ b/Documentation/hwmon/f71882fg @@ -2,10 +2,6 @@ Kernel driver f71882fg ====================== Supported chips: - * Fintek F71808E - Prefix: 'f71808fg' - Addresses scanned: none, address read from Super I/O config space - Datasheet: Not public * Fintek F71858FG Prefix: 'f71858fg' Addresses scanned: none, address read from Super I/O config space diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 0fba829..4d4d09b 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -332,11 +332,11 @@ config SENSORS_F71805F will be called f71805f. config SENSORS_F71882FG - tristate "Fintek F71808E, F71858FG, F71862FG, F71882FG, F71889FG and F8000" + tristate "Fintek F71858FG, F71862FG, F71882FG, F71889FG and F8000" depends on EXPERIMENTAL help - If you say yes here you get support for hardware monitoring features - of the Fintek F71808E, F71858FG, F71862FG/71863FG, F71882FG/F71883FG, + If you say yes here you get support for hardware monitoring + features of the Fintek F71858FG, F71862FG/71863FG, F71882FG/F71883FG, F71889FG and F8000 Super-I/O chips. This driver can also be built as a module. If so, the module diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 6207120..537841e 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -45,7 +45,6 @@ #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ #define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */ -#define SIO_F71808_ID 0x0901 /* Chipset ID */ #define SIO_F71858_ID 0x0507 /* Chipset ID */ #define SIO_F71862_ID 0x0601 /* Chipset ID */ #define SIO_F71882_ID 0x0541 /* Chipset ID */ @@ -97,10 +96,9 @@ static unsigned short force_id; module_param(force_id, ushort, 0); MODULE_PARM_DESC(force_id, "Override the detected device ID"); -enum chips { f71808fg, f71858fg, f71862fg, f71882fg, f71889fg, f8000 }; +enum chips { f71858fg, f71862fg, f71882fg, f71889fg, f8000 }; static const char *f71882fg_names[] = { - "f71808fg", "f71858fg", "f71862fg", "f71882fg", @@ -308,8 +306,8 @@ static struct sensor_device_attribute_2 f71858fg_in_temp_attr[] = { SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2), }; -/* In attr common to the f71862fg, f71882fg and f71889fg */ -static struct sensor_device_attribute_2 fxxxx_in_attr[] = { +/* Temp and in attr common to the f71862fg, f71882fg and f71889fg */ +static struct sensor_device_attribute_2 fxxxx_in_temp_attr[] = { SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0), SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1), SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2), @@ -319,22 +317,6 @@ 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), -}; - -/* In attr for the f71808fg */ -static struct sensor_device_attribute_2 f71808_in_attr[] = { - SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0), - SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1), - SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2), - SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3), - SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4), - SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5), - SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 7), - SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 8), -}; - -/* Temp attr common to the f71808fg, f71862fg, f71882fg and f71889fg */ -static struct sensor_device_attribute_2 fxxxx_temp_attr[] = { SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 1), SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max, store_temp_max, 0, 1), @@ -373,10 +355,6 @@ static struct sensor_device_attribute_2 fxxxx_temp_attr[] = { store_temp_beep, 0, 6), SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2), SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2), -}; - -/* Temp and in attr common to the f71862fg, f71882fg and f71889fg */ -static struct sensor_device_attribute_2 f71862_temp_attr[] = { SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3), SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max, store_temp_max, 0, 3), @@ -1011,11 +989,6 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) data->temp_type[1] = 6; break; } - } else if (data->type == f71808fg) { - reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE); - data->temp_type[1] = (reg & 0x02) ? 2 : 4; - data->temp_type[2] = (reg & 0x04) ? 2 : 4; - } else { reg2 = f71882fg_read8(data, F71882FG_REG_PECI); if ((reg2 & 0x03) == 0x01) @@ -1898,8 +1871,7 @@ static ssize_t store_pwm_auto_point_temp(struct device *dev, val /= 1000; - if (data->type == f71889fg - || data->type == f71808fg) + if (data->type == f71889fg) val = SENSORS_LIMIT(val, -128, 127); else val = SENSORS_LIMIT(val, 0, 127); @@ -2002,28 +1974,8 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) /* fall through! */ case f71862fg: err = f71882fg_create_sysfs_files(pdev, - f71862_temp_attr, - ARRAY_SIZE(f71862_temp_attr)); - if (err) - goto exit_unregister_sysfs; - err = f71882fg_create_sysfs_files(pdev, - fxxxx_in_attr, - ARRAY_SIZE(fxxxx_in_attr)); - if (err) - goto exit_unregister_sysfs; - err = f71882fg_create_sysfs_files(pdev, - fxxxx_temp_attr, - ARRAY_SIZE(fxxxx_temp_attr)); - break; - case f71808fg: - err = f71882fg_create_sysfs_files(pdev, - f71808_in_attr, - ARRAY_SIZE(f71808_in_attr)); - if (err) - goto exit_unregister_sysfs; - err = f71882fg_create_sysfs_files(pdev, - fxxxx_temp_attr, - ARRAY_SIZE(fxxxx_temp_attr)); + fxxxx_in_temp_attr, + ARRAY_SIZE(fxxxx_in_temp_attr)); break; case f8000: err = f71882fg_create_sysfs_files(pdev, @@ -2050,7 +2002,6 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) case f71862fg: err = (data->pwm_enable & 0x15) != 0x15; break; - case f71808fg: case f71882fg: case f71889fg: err = 0; @@ -2096,7 +2047,6 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) f8000_auto_pwm_attr, ARRAY_SIZE(f8000_auto_pwm_attr)); break; - case f71808fg: case f71889fg: for (i = 0; i < nr_fans; i++) { data->pwm_auto_point_mapping[i] = @@ -2176,22 +2126,8 @@ static int f71882fg_remove(struct platform_device *pdev) /* fall through! */ case f71862fg: f71882fg_remove_sysfs_files(pdev, - f71862_temp_attr, - ARRAY_SIZE(f71862_temp_attr)); - f71882fg_remove_sysfs_files(pdev, - fxxxx_in_attr, - ARRAY_SIZE(fxxxx_in_attr)); - f71882fg_remove_sysfs_files(pdev, - fxxxx_temp_attr, - ARRAY_SIZE(fxxxx_temp_attr)); - break; - case f71808fg: - f71882fg_remove_sysfs_files(pdev, - f71808_in_attr, - ARRAY_SIZE(f71808_in_attr)); - f71882fg_remove_sysfs_files(pdev, - fxxxx_temp_attr, - ARRAY_SIZE(fxxxx_temp_attr)); + fxxxx_in_temp_attr, + ARRAY_SIZE(fxxxx_in_temp_attr)); break; case f8000: f71882fg_remove_sysfs_files(pdev, @@ -2259,9 +2195,6 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address, devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID); switch (devid) { - case SIO_F71808_ID: - sio_data->type = f71808fg; - break; case SIO_F71858_ID: sio_data->type = f71858fg; break; -- cgit v0.10.2 From d5ed3a4af77b851b6271ad3d9abc4c57fa3ce0f5 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 19 Aug 2010 14:13:33 -0700 Subject: lib/radix-tree.c: fix overflow in radix_tree_range_tag_if_tagged() When radix_tree_maxindex() is ~0UL, it can happen that scanning overflows index and tree traversal code goes astray reading memory until it hits unreadable memory. Check for overflow and exit in that case. Signed-off-by: Jan Kara Cc: Christoph Hellwig Cc: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/lib/radix-tree.c b/lib/radix-tree.c index e907858..5b7d462 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -625,6 +625,8 @@ EXPORT_SYMBOL(radix_tree_tag_get); * * The function returns number of leaves where the tag was set and sets * *first_indexp to the first unscanned index. + * WARNING! *first_indexp can wrap if last_index is ULONG_MAX. Caller must + * be prepared to handle that. */ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root, unsigned long *first_indexp, unsigned long last_index, @@ -675,7 +677,8 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root, next: /* Go to next item at level determined by 'shift' */ index = ((index >> shift) + 1) << shift; - if (index > last_index) + /* Overflow can happen when last_index is ~0UL... */ + if (index > last_index || !index) break; if (tagged >= nr_to_tag) break; diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 7262aac..c09ef52 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -836,7 +836,8 @@ void tag_pages_for_writeback(struct address_space *mapping, spin_unlock_irq(&mapping->tree_lock); WARN_ON_ONCE(tagged > WRITEBACK_TAG_BATCH); cond_resched(); - } while (tagged >= WRITEBACK_TAG_BATCH); + /* We check 'start' to handle wrapping when end == ~0UL */ + } while (tagged >= WRITEBACK_TAG_BATCH && start); } EXPORT_SYMBOL(tag_pages_for_writeback); -- cgit v0.10.2 From 944645c33e4ada914f4c045525a9293610085ccd Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Thu, 19 Aug 2010 14:13:34 -0700 Subject: s5pc110: SDHCI-s3c can override host capabilities Each board can override the default sdhci host capabilities. Some board has broken features by hardwares and support 8-bit bandwidth. Signed-off-by: Kyungmin Park Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/arm/plat-samsung/dev-hsmmc.c b/arch/arm/plat-samsung/dev-hsmmc.c index b0f93f1..9d2be09 100644 --- a/arch/arm/plat-samsung/dev-hsmmc.c +++ b/arch/arm/plat-samsung/dev-hsmmc.c @@ -70,4 +70,6 @@ void s3c_sdhci0_set_platdata(struct s3c_sdhci_platdata *pd) set->cfg_gpio = pd->cfg_gpio; if (pd->cfg_card) set->cfg_card = pd->cfg_card; + if (pd->host_caps) + set->host_caps = pd->host_caps; } diff --git a/arch/arm/plat-samsung/dev-hsmmc1.c b/arch/arm/plat-samsung/dev-hsmmc1.c index 1504fd8..a6c8295 100644 --- a/arch/arm/plat-samsung/dev-hsmmc1.c +++ b/arch/arm/plat-samsung/dev-hsmmc1.c @@ -70,4 +70,6 @@ void s3c_sdhci1_set_platdata(struct s3c_sdhci_platdata *pd) set->cfg_gpio = pd->cfg_gpio; if (pd->cfg_card) set->cfg_card = pd->cfg_card; + if (pd->host_caps) + set->host_caps = pd->host_caps; } diff --git a/arch/arm/plat-samsung/dev-hsmmc2.c b/arch/arm/plat-samsung/dev-hsmmc2.c index b28ef17..cb0d714 100644 --- a/arch/arm/plat-samsung/dev-hsmmc2.c +++ b/arch/arm/plat-samsung/dev-hsmmc2.c @@ -71,4 +71,6 @@ void s3c_sdhci2_set_platdata(struct s3c_sdhci_platdata *pd) set->cfg_gpio = pd->cfg_gpio; if (pd->cfg_card) set->cfg_card = pd->cfg_card; + if (pd->host_caps) + set->host_caps = pd->host_caps; } -- cgit v0.10.2 From 930a6f70fa3b9c79a57dd6850ef9cb1efa470575 Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Thu, 19 Aug 2010 14:13:35 -0700 Subject: s5pc110: SDHCI-s3c support on s5pc110 s5pc110 (aka s5pv210) uses the same SDHCI IP. Signed-off-by: Kyungmin Park Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 283190b..68d1279 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -132,7 +132,7 @@ config MMC_SDHCI_CNS3XXX config MMC_SDHCI_S3C tristate "SDHCI support on Samsung S3C SoC" - depends on MMC_SDHCI && (PLAT_S3C24XX || PLAT_S3C64XX) + depends on MMC_SDHCI && PLAT_SAMSUNG help This selects the Secure Digital Host Controller Interface (SDHCI) often referrered to as the HSMMC block in some of the Samsung S3C -- cgit v0.10.2 From 5193250168ccdf87364e35a11965336dc088578c Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Thu, 19 Aug 2010 14:13:35 -0700 Subject: sdhci: add no hi-speed bit quirk support Some SDHCI controllers like s5pc110 don't have an HISPD bit in the HOSTCTL register. Signed-off-by: Kyungmin Park Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 7855121..401527d 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1180,7 +1180,8 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) else ctrl &= ~SDHCI_CTRL_4BITBUS; - if (ios->timing == MMC_TIMING_SD_HS) + if (ios->timing == MMC_TIMING_SD_HS && + !(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)) ctrl |= SDHCI_CTRL_HISPD; else ctrl &= ~SDHCI_CTRL_HISPD; diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 036cfae..d316bc7 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -245,6 +245,8 @@ struct sdhci_host { #define SDHCI_QUIRK_MISSING_CAPS (1<<27) /* Controller uses Auto CMD12 command to stop the transfer */ #define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 (1<<28) +/* Controller doesn't have HISPD bit field in HI-SPEED SD card */ +#define SDHCI_QUIRK_NO_HISPD_BIT (1<<29) int irq; /* Device IRQ */ void __iomem * ioaddr; /* Mapped address */ -- cgit v0.10.2 From f522886e202a34a2191dd5d471b3c4d46410a9a0 Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Thu, 19 Aug 2010 14:13:37 -0700 Subject: drivers/mmc/host/sdhci-s3c.c: use the correct mutex and card detect function There's some merge problem between sdhic core and sdhci-s3c host. After mutex is changed to spinlock. It needs to use use spin lock functions and use the correct card detection function. Signed-off-by: Kyungmin Park Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 0a7f261..71ad416 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -242,7 +242,7 @@ static void sdhci_s3c_notify_change(struct platform_device *dev, int state) { struct sdhci_host *host = platform_get_drvdata(dev); if (host) { - mutex_lock(&host->lock); + spin_lock(&host->lock); if (state) { dev_dbg(&dev->dev, "card inserted.\n"); host->flags &= ~SDHCI_DEVICE_DEAD; @@ -252,8 +252,8 @@ static void sdhci_s3c_notify_change(struct platform_device *dev, int state) host->flags |= SDHCI_DEVICE_DEAD; host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; } - sdhci_card_detect(host); - mutex_unlock(&host->lock); + tasklet_schedule(&host->card_tasklet); + spin_unlock(&host->lock); } } -- cgit v0.10.2 From be71cf2202971e50ce4953d473649c724799eb8a Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro Date: Thu, 19 Aug 2010 14:13:38 -0700 Subject: oom: fix NULL pointer dereference Commit b940fd7035 ("oom: remove unnecessary code and cleanup") added an unnecessary NULL pointer dereference. remove it. Signed-off-by: KOSAKI Motohiro Reviewed-by: Minchan Kim Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 5014e50..17d48a6 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -401,10 +401,9 @@ static void dump_header(struct task_struct *p, gfp_t gfp_mask, int order, static int oom_kill_task(struct task_struct *p, struct mem_cgroup *mem) { p = find_lock_task_mm(p); - if (!p) { - task_unlock(p); + if (!p) return 1; - } + pr_err("Killed process %d (%s) total-vm:%lukB, anon-rss:%lukB, file-rss:%lukB\n", task_pid_nr(p), p->comm, K(p->mm->total_vm), K(get_mm_counter(p->mm, MM_ANONPAGES)), -- cgit v0.10.2 From b52723c5607f7684c2c0c075f86f86da0d7fb6d0 Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro Date: Thu, 19 Aug 2010 14:13:39 -0700 Subject: oom: fix tasklist_lock leak Commit 0aad4b3124 ("oom: fold __out_of_memory into out_of_memory") introduced a tasklist_lock leak. Then it caused following obvious danger warnings and panic. ================================================ [ BUG: lock held when returning to user space! ] ------------------------------------------------ rsyslogd/1422 is leaving the kernel with locks still held! 1 lock held by rsyslogd/1422: #0: (tasklist_lock){.+.+.+}, at: [] out_of_memory+0x164/0x3f0 BUG: scheduling while atomic: rsyslogd/1422/0x00000002 INFO: lockdep is turned off. This patch fixes it. Signed-off-by: KOSAKI Motohiro Reviewed-by: Minchan Kim Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 17d48a6..c48c5ef 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -646,6 +646,7 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, unsigned long freed = 0; unsigned int points; enum oom_constraint constraint = CONSTRAINT_NONE; + int killed = 0; blocking_notifier_call_chain(&oom_notify_list, 0, &freed); if (freed > 0) @@ -683,7 +684,7 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, if (!oom_kill_process(current, gfp_mask, order, 0, totalpages, NULL, nodemask, "Out of memory (oom_kill_allocating_task)")) - return; + goto out; } retry: @@ -691,7 +692,7 @@ retry: constraint == CONSTRAINT_MEMORY_POLICY ? nodemask : NULL); if (PTR_ERR(p) == -1UL) - return; + goto out; /* Found nothing?!?! Either we hang forever, or we panic. */ if (!p) { @@ -703,13 +704,15 @@ retry: if (oom_kill_process(p, gfp_mask, order, points, totalpages, NULL, nodemask, "Out of memory")) goto retry; + killed = 1; +out: read_unlock(&tasklist_lock); /* * Give "p" a good chance of killing itself before we * retry to allocate memory unless "p" is current */ - if (!test_thread_flag(TIF_MEMDIE)) + if (killed && !test_thread_flag(TIF_MEMDIE)) schedule_timeout_uninterruptible(1); } -- cgit v0.10.2 From 8d6c83f0ba5e1bd1e8bb2e3c7de4c276dc247f99 Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro Date: Thu, 19 Aug 2010 14:13:39 -0700 Subject: oom: __task_cred() need rcu_read_lock() dump_tasks() needs to hold the RCU read lock around its access of the target task's UID. To this end it should use task_uid() as it only needs that one thing from the creds. The fact that dump_tasks() holds tasklist_lock is insufficient to prevent the target process replacing its credentials on another CPU. Then, this patch change to call rcu_read_lock() explicitly. =================================================== [ INFO: suspicious rcu_dereference_check() usage. ] --------------------------------------------------- mm/oom_kill.c:410 invoked rcu_dereference_check() without protection! other info that might help us debug this: rcu_scheduler_active = 1, debug_locks = 1 4 locks held by kworker/1:2/651: #0: (events){+.+.+.}, at: [] process_one_work+0x137/0x4a0 #1: (moom_work){+.+...}, at: [] process_one_work+0x137/0x4a0 #2: (tasklist_lock){.+.+..}, at: [] out_of_memory+0x164/0x3f0 #3: (&(&p->alloc_lock)->rlock){+.+...}, at: [] find_lock_task_mm+0x2e/0x70 Signed-off-by: KOSAKI Motohiro Signed-off-by: David Howells Acked-by: Paul E. McKenney Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/oom_kill.c b/mm/oom_kill.c index c48c5ef..fc81cb2 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -372,7 +372,7 @@ static void dump_tasks(const struct mem_cgroup *mem) } pr_info("[%5d] %5d %5d %8lu %8lu %3u %3d %5d %s\n", - task->pid, __task_cred(task)->uid, task->tgid, + task->pid, task_uid(task), task->tgid, task->mm->total_vm, get_mm_rss(task->mm), task_cpu(task), task->signal->oom_adj, task->signal->oom_score_adj, task->comm); -- cgit v0.10.2 From f3c072ad727617f00bffae17dba8cd895f5b7bdb Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 19 Aug 2010 14:13:40 -0700 Subject: uml: fix compile error in dma_get_cache_alignment() Fix uml compile error: include/linux/dma-mapping.h:145: error: redefinition of 'dma_get_cache_alignment' arch/um/include/asm/dma-mapping.h:99: note: previous definition of 'dma_get_cache_alignment' was here Introduced by commit 4565f0170dfc ("dma-mapping: unify dma_get_cache_alignment implementations") Signed-off-by: Miklos Szeredi Cc: Jeff Dike Cc: FUJITA Tomonori Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/um/include/asm/dma-mapping.h b/arch/um/include/asm/dma-mapping.h index 17a2cb5..1f469e80 100644 --- a/arch/um/include/asm/dma-mapping.h +++ b/arch/um/include/asm/dma-mapping.h @@ -95,13 +95,6 @@ dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) -static inline int -dma_get_cache_alignment(void) -{ - BUG(); - return(0); -} - static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction) -- cgit v0.10.2 From 626115cda9a31d7618cfd5ca8928811e5947d360 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 19 Aug 2010 14:13:42 -0700 Subject: drivers/scsi/qla4xxx: fix build gcc-4.0.2: drivers/scsi/qla4xxx/ql4_os.c: In function 'qla4_8xxx_error_recovery': drivers/scsi/qla4xxx/ql4_glbl.h:135: sorry, unimplemented: inlining failed in call to 'qla4_8xxx_set_drv_active': function body not available drivers/scsi/qla4xxx/ql4_os.c:2377: sorry, unimplemented: called from here drivers/scsi/qla4xxx/ql4_glbl.h:135: sorry, unimplemented: inlining failed in call to 'qla4_8xxx_set_drv_active': function body not available drivers/scsi/qla4xxx/ql4_os.c:2393: sorry, unimplemented: called from here Cc: Ravi Anand Cc: Vikas Chaudhary Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index f065204..95a26fb 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h @@ -132,7 +132,7 @@ void qla4_8xxx_idc_unlock(struct scsi_qla_host *ha); int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha); void qla4_8xxx_need_qsnt_handler(struct scsi_qla_host *ha); void qla4_8xxx_clear_drv_active(struct scsi_qla_host *ha); -inline void qla4_8xxx_set_drv_active(struct scsi_qla_host *ha); +void qla4_8xxx_set_drv_active(struct scsi_qla_host *ha); extern int ql4xextended_error_logging; extern int ql4xdiscoverywait; diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c index e031a73..5d4a382 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.c +++ b/drivers/scsi/qla4xxx/ql4_nx.c @@ -1418,7 +1418,7 @@ static int qla4_8xxx_rcvpeg_ready(struct scsi_qla_host *ha) return QLA_SUCCESS; } -inline void +void qla4_8xxx_set_drv_active(struct scsi_qla_host *ha) { uint32_t drv_active; -- cgit v0.10.2 From 1ee41680572971e34d90d5f584daf33195ec6dcb Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Thu, 19 Aug 2010 14:13:43 -0700 Subject: Documentation: kernel-locking: mutex_trylock cannot be used in interrupt context Chapter 6 is right about mutex_trylock, but chapter 10 wasn't. This error was introduced during semaphore-to-mutex conversion of the Unreliable guide. :-) If user context which performs mutex_lock() or mutex_trylock() is preempted by interrupt context which performs mutex_trylock() on the same mutex instance, a deadlock occurs. This is because these functions do not disable local IRQs when they operate on mutex->wait_lock. Signed-off-by: Stefan Richter Acked-by: Rusty Russell Cc: Matthew Wilcox Cc: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/DocBook/kernel-locking.tmpl b/Documentation/DocBook/kernel-locking.tmpl index 084f6ad..0b1a3f9 100644 --- a/Documentation/DocBook/kernel-locking.tmpl +++ b/Documentation/DocBook/kernel-locking.tmpl @@ -1922,9 +1922,12 @@ machines due to caching. mutex_lock() - There is a mutex_trylock() which can be - used inside interrupt context, as it will not sleep. + There is a mutex_trylock() which does not + sleep. Still, it must not be used inside interrupt context since + its implementation is not safe for that. mutex_unlock() will also never sleep. + It cannot be used in interrupt context either since a mutex + must be released by the same task that acquired it. -- cgit v0.10.2 From a4724ed6f084fd294b001103a68c3196eb60364c Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 20 Aug 2010 19:52:45 +1000 Subject: MAINTAINERS: Fix ozlabs.org mailing list addresses All these lists moved to lists.ozlabs.org quite a while ago. Signed-off-by: Stephen Rothwell Signed-off-by: Linus Torvalds diff --git a/MAINTAINERS b/MAINTAINERS index b5b8baa..433f353 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -456,7 +456,7 @@ F: drivers/infiniband/hw/amso1100/ AOA (Apple Onboard Audio) ALSA DRIVER M: Johannes Berg -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Maintained F: sound/aoa/ @@ -1472,8 +1472,8 @@ F: include/linux/can/platform/ CELL BROADBAND ENGINE ARCHITECTURE M: Arnd Bergmann -L: linuxppc-dev@ozlabs.org -L: cbe-oss-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org +L: cbe-oss-dev@lists.ozlabs.org W: http://www.ibm.com/developerworks/power/cell/ S: Supported F: arch/powerpc/include/asm/cell*.h @@ -2371,13 +2371,13 @@ F: include/linux/fb.h FREESCALE DMA DRIVER M: Li Yang M: Zhang Wei -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org S: Maintained F: drivers/dma/fsldma.* FREESCALE I2C CPM DRIVER M: Jochen Friedrich -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org L: linux-i2c@vger.kernel.org S: Maintained F: drivers/i2c/busses/i2c-cpm.c @@ -2393,7 +2393,7 @@ F: drivers/video/imxfb.c FREESCALE SOC FS_ENET DRIVER M: Pantelis Antoniou M: Vitaly Bordug -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org L: netdev@vger.kernel.org S: Maintained F: drivers/net/fs_enet/ @@ -2401,7 +2401,7 @@ F: include/linux/fs_enet_pd.h FREESCALE QUICC ENGINE LIBRARY M: Timur Tabi -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org S: Supported F: arch/powerpc/sysdev/qe_lib/ F: arch/powerpc/include/asm/*qe.h @@ -2409,27 +2409,27 @@ F: arch/powerpc/include/asm/*qe.h FREESCALE USB PERIPHERAL DRIVERS M: Li Yang L: linux-usb@vger.kernel.org -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org S: Maintained F: drivers/usb/gadget/fsl* FREESCALE QUICC ENGINE UCC ETHERNET DRIVER M: Li Yang L: netdev@vger.kernel.org -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org S: Maintained F: drivers/net/ucc_geth* FREESCALE QUICC ENGINE UCC UART DRIVER M: Timur Tabi -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org S: Supported F: drivers/serial/ucc_uart.c FREESCALE SOC SOUND DRIVERS M: Timur Tabi L: alsa-devel@alsa-project.org (moderated for non-subscribers) -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org S: Supported F: sound/soc/fsl/fsl* F: sound/soc/fsl/mpc8610_hpcd.c @@ -2564,7 +2564,7 @@ F: mm/memory-failure.c F: mm/hwpoison-inject.c HYPERVISOR VIRTUAL CONSOLE DRIVER -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org S: Odd Fixes F: drivers/char/hvc_* @@ -3476,7 +3476,7 @@ F: drivers/usb/misc/legousbtower.c LGUEST M: Rusty Russell -L: lguest@ozlabs.org +L: lguest@lists.ozlabs.org W: http://lguest.ozlabs.org/ S: Maintained F: Documentation/lguest/ @@ -3495,7 +3495,7 @@ LINUX FOR POWERPC (32-BIT AND 64-BIT) M: Benjamin Herrenschmidt M: Paul Mackerras W: http://www.penguinppc.org/ -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org Q: http://patchwork.ozlabs.org/project/linuxppc-dev/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git S: Supported @@ -3505,14 +3505,14 @@ F: arch/powerpc/ LINUX FOR POWER MACINTOSH M: Benjamin Herrenschmidt W: http://www.penguinppc.org/ -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org S: Maintained F: arch/powerpc/platforms/powermac/ F: drivers/macintosh/ LINUX FOR POWERPC EMBEDDED MPC5XXX M: Grant Likely -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org T: git git://git.secretlab.ca/git/linux-2.6.git S: Maintained F: arch/powerpc/platforms/512x/ @@ -3522,7 +3522,7 @@ LINUX FOR POWERPC EMBEDDED PPC4XX M: Josh Boyer M: Matt Porter W: http://www.penguinppc.org/ -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/jwboyer/powerpc-4xx.git S: Maintained F: arch/powerpc/platforms/40x/ @@ -3531,7 +3531,7 @@ F: arch/powerpc/platforms/44x/ LINUX FOR POWERPC EMBEDDED XILINX VIRTEX M: Grant Likely W: http://wiki.secretlab.ca/index.php/Linux_on_Xilinx_Virtex -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org T: git git://git.secretlab.ca/git/linux-2.6.git S: Maintained F: arch/powerpc/*/*virtex* @@ -3541,20 +3541,20 @@ LINUX FOR POWERPC EMBEDDED PPC8XX M: Vitaly Bordug M: Marcelo Tosatti W: http://www.penguinppc.org/ -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org S: Maintained F: arch/powerpc/platforms/8xx/ LINUX FOR POWERPC EMBEDDED PPC83XX AND PPC85XX M: Kumar Gala W: http://www.penguinppc.org/ -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org S: Maintained F: arch/powerpc/platforms/83xx/ LINUX FOR POWERPC PA SEMI PWRFICIENT M: Olof Johansson -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org S: Maintained F: arch/powerpc/platforms/pasemi/ F: drivers/*/*pasemi* @@ -4601,14 +4601,14 @@ F: drivers/ata/sata_promise.* PS3 NETWORK SUPPORT M: Geoff Levand L: netdev@vger.kernel.org -L: cbe-oss-dev@ozlabs.org +L: cbe-oss-dev@lists.ozlabs.org S: Maintained F: drivers/net/ps3_gelic_net.* PS3 PLATFORM SUPPORT M: Geoff Levand -L: linuxppc-dev@ozlabs.org -L: cbe-oss-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org +L: cbe-oss-dev@lists.ozlabs.org S: Maintained F: arch/powerpc/boot/ps3* F: arch/powerpc/include/asm/lv1call.h @@ -4622,7 +4622,7 @@ F: sound/ppc/snd_ps3* PS3VRAM DRIVER M: Jim Paris -L: cbe-oss-dev@ozlabs.org +L: cbe-oss-dev@lists.ozlabs.org S: Maintained F: drivers/block/ps3vram.c @@ -5068,7 +5068,7 @@ F: drivers/mmc/host/sdhci.* SECURE DIGITAL HOST CONTROLLER INTERFACE, OPEN FIRMWARE BINDINGS (SDHCI-OF) M: Anton Vorontsov -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org L: linux-mmc@vger.kernel.org S: Maintained F: drivers/mmc/host/sdhci-of.* @@ -5485,8 +5485,8 @@ F: drivers/net/spider_net* SPU FILE SYSTEM M: Jeremy Kerr -L: linuxppc-dev@ozlabs.org -L: cbe-oss-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org +L: cbe-oss-dev@lists.ozlabs.org W: http://www.ibm.com/developerworks/power/cell/ S: Supported F: Documentation/filesystems/spufs.txt -- cgit v0.10.2 From f6143a9b732977859cb6e04c604d04976aa5ccbd Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 20 Aug 2010 19:56:31 +1000 Subject: Documentation: fix ozlabs.org mailing list address This list moved to lists.ozlabs.org quite some time ago. Signed-off-by: Stephen Rothwell Signed-off-by: Linus Torvalds diff --git a/Documentation/powerpc/hvcs.txt b/Documentation/powerpc/hvcs.txt index f93462c..6d8be34 100644 --- a/Documentation/powerpc/hvcs.txt +++ b/Documentation/powerpc/hvcs.txt @@ -560,7 +560,7 @@ The proper channel for reporting bugs is either through the Linux OS distribution company that provided your OS or by posting issues to the PowerPC development mailing list at: -linuxppc-dev@ozlabs.org +linuxppc-dev@lists.ozlabs.org This request is to provide a documented and searchable public exchange of the problems and solutions surrounding this driver for the benefit of -- cgit v0.10.2 From cfe3fdadb16162327773ef01a575a32000b8c7f4 Mon Sep 17 00:00:00 2001 From: Tilman Sauerbeck Date: Fri, 20 Aug 2010 14:01:47 -0700 Subject: mtd: nand: Fix probe of Samsung NAND chips Apparently, the check for a 6-byte ID string introduced by commit 426c457a3216fac74e3d44dd39729b0689f4c7ab ("mtd: nand: extend NAND flash detection to new MLC chips") is NOT sufficient to determine whether or not a Samsung chip uses their new MLC detection scheme or the old, standard scheme. This adds a condition to check cell type. Signed-off-by: Tilman Sauerbeck Signed-off-by: Brian Norris Signed-off-by: David Woodhouse Cc: stable@kernel.org diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index a22ed7b..d551ddd 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2866,6 +2866,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, */ if (id_data[0] == id_data[6] && id_data[1] == id_data[7] && id_data[0] == NAND_MFR_SAMSUNG && + (chip->cellinfo & NAND_CI_CELLTYPE_MSK) && id_data[5] != 0x00) { /* Calc pagesize */ mtd->writesize = 2048 << (extid & 0x03); -- cgit v0.10.2 From 8558f59edf935cf5ee5ffc29a9e9458fd9a71be1 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Mon, 16 Aug 2010 17:09:52 +0200 Subject: setlocalversion: Ignote SCMs above the linux source tree Dan McGee writes: > Note that when in git, you get the appended "+" sign. If > LOCALVERSION_AUTO is set, you will get something like > "eee-gb01b08c-dirty" (whereas the copy of the tree in /tmp still > returns "eee"). It doesn't matter whether the working tree is dirty or > clean. > > Is there a way to disable this? I'm building from a clean tarball that > just happens to be unpacked inside a git repository. One would think > setting LOCALVERSION_AUTO to false would do it, but no such luck... Fix this by checking if the kernel source tree is the root of the git or hg repository. No fix for svn: If the kernel source is not tracked in the svn repository, it works as expected, otherwise determining the 'repository root' is not really a defined task. Reported-and-tested-by: Dan McGee Signed-off-by: Michal Marek diff --git a/scripts/setlocalversion b/scripts/setlocalversion index e90a91c..057b6b3 100755 --- a/scripts/setlocalversion +++ b/scripts/setlocalversion @@ -43,7 +43,7 @@ scm_version() fi # Check for git and a git repo. - if head=`git rev-parse --verify --short HEAD 2>/dev/null`; then + if test -d .git && head=`git rev-parse --verify --short HEAD 2>/dev/null`; then # If we are at a tagged commit (like "v2.6.30-rc6"), we ignore # it, because this version is defined in the top level Makefile. @@ -85,7 +85,7 @@ scm_version() fi # Check for mercurial and a mercurial repo. - if hgid=`hg id 2>/dev/null`; then + if test -d .hg && hgid=`hg id 2>/dev/null`; then tag=`printf '%s' "$hgid" | cut -s -d' ' -f2` # Do we have an untagged version? -- cgit v0.10.2 From 297c5eee372478fc32fec5fe8eed711eedb13f3d Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 20 Aug 2010 16:24:55 -0700 Subject: mm: make the vma list be doubly linked It's a really simple list, and several of the users want to go backwards in it to find the previous vma. So rather than have to look up the previous entry with 'find_vma_prev()' or something similar, just make it doubly linked instead. Tested-by: Ian Campbell Signed-off-by: Linus Torvalds diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index b8bb9a6..ee7e258 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -134,7 +134,7 @@ struct vm_area_struct { within vm_mm. */ /* linked list of VM areas per task, sorted by address */ - struct vm_area_struct *vm_next; + struct vm_area_struct *vm_next, *vm_prev; pgprot_t vm_page_prot; /* Access permissions of this VMA. */ unsigned long vm_flags; /* Flags, see mm.h. */ diff --git a/kernel/fork.c b/kernel/fork.c index 856eac3..b7e9d60 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -300,7 +300,7 @@ out: #ifdef CONFIG_MMU static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) { - struct vm_area_struct *mpnt, *tmp, **pprev; + struct vm_area_struct *mpnt, *tmp, *prev, **pprev; struct rb_node **rb_link, *rb_parent; int retval; unsigned long charge; @@ -328,6 +328,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) if (retval) goto out; + prev = NULL; for (mpnt = oldmm->mmap; mpnt; mpnt = mpnt->vm_next) { struct file *file; @@ -359,7 +360,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) goto fail_nomem_anon_vma_fork; tmp->vm_flags &= ~VM_LOCKED; tmp->vm_mm = mm; - tmp->vm_next = NULL; + tmp->vm_next = tmp->vm_prev = NULL; file = tmp->vm_file; if (file) { struct inode *inode = file->f_path.dentry->d_inode; @@ -392,6 +393,8 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) */ *pprev = tmp; pprev = &tmp->vm_next; + tmp->vm_prev = prev; + prev = tmp; __vma_link_rb(mm, tmp, rb_link, rb_parent); rb_link = &tmp->vm_rb.rb_right; diff --git a/mm/mmap.c b/mm/mmap.c index 3100333..331e51a 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -388,17 +388,23 @@ static inline void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma, struct vm_area_struct *prev, struct rb_node *rb_parent) { + struct vm_area_struct *next; + + vma->vm_prev = prev; if (prev) { - vma->vm_next = prev->vm_next; + next = prev->vm_next; prev->vm_next = vma; } else { mm->mmap = vma; if (rb_parent) - vma->vm_next = rb_entry(rb_parent, + next = rb_entry(rb_parent, struct vm_area_struct, vm_rb); else - vma->vm_next = NULL; + next = NULL; } + vma->vm_next = next; + if (next) + next->vm_prev = vma; } void __vma_link_rb(struct mm_struct *mm, struct vm_area_struct *vma, @@ -483,7 +489,11 @@ static inline void __vma_unlink(struct mm_struct *mm, struct vm_area_struct *vma, struct vm_area_struct *prev) { - prev->vm_next = vma->vm_next; + struct vm_area_struct *next = vma->vm_next; + + prev->vm_next = next; + if (next) + next->vm_prev = prev; rb_erase(&vma->vm_rb, &mm->mm_rb); if (mm->mmap_cache == vma) mm->mmap_cache = prev; @@ -1915,6 +1925,7 @@ detach_vmas_to_be_unmapped(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long addr; insertion_point = (prev ? &prev->vm_next : &mm->mmap); + vma->vm_prev = NULL; do { rb_erase(&vma->vm_rb, &mm->mm_rb); mm->map_count--; @@ -1922,6 +1933,8 @@ detach_vmas_to_be_unmapped(struct mm_struct *mm, struct vm_area_struct *vma, vma = vma->vm_next; } while (vma && vma->vm_start < end); *insertion_point = vma; + if (vma) + vma->vm_prev = prev; tail_vma->vm_next = NULL; if (mm->unmap_area == arch_unmap_area) addr = prev ? prev->vm_end : mm->mmap_base; diff --git a/mm/nommu.c b/mm/nommu.c index efa9a38..88ff091 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -604,7 +604,7 @@ static void protect_vma(struct vm_area_struct *vma, unsigned long flags) */ static void add_vma_to_mm(struct mm_struct *mm, struct vm_area_struct *vma) { - struct vm_area_struct *pvma, **pp; + struct vm_area_struct *pvma, **pp, *next; struct address_space *mapping; struct rb_node **p, *parent; @@ -664,8 +664,11 @@ static void add_vma_to_mm(struct mm_struct *mm, struct vm_area_struct *vma) break; } - vma->vm_next = *pp; + next = *pp; *pp = vma; + vma->vm_next = next; + if (next) + next->vm_prev = vma; } /* -- cgit v0.10.2 From 7798330ac8114c731cfab83e634c6ecedaa233d7 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 20 Aug 2010 16:39:25 -0700 Subject: mm: make the mlock() stack guard page checks stricter If we've split the stack vma, only the lowest one has the guard page. Now that we have a doubly linked list of vma's, checking this is trivial. Tested-by: Ian Campbell Signed-off-by: Linus Torvalds diff --git a/mm/mlock.c b/mm/mlock.c index 49e5e4c..cbae7c5 100644 --- a/mm/mlock.c +++ b/mm/mlock.c @@ -135,6 +135,19 @@ void munlock_vma_page(struct page *page) } } +/* Is the vma a continuation of the stack vma above it? */ +static inline int vma_stack_continue(struct vm_area_struct *vma, unsigned long addr) +{ + return vma && (vma->vm_end == addr) && (vma->vm_flags & VM_GROWSDOWN); +} + +static inline int stack_guard_page(struct vm_area_struct *vma, unsigned long addr) +{ + return (vma->vm_flags & VM_GROWSDOWN) && + (vma->vm_start == addr) && + !vma_stack_continue(vma->vm_prev, addr); +} + /** * __mlock_vma_pages_range() - mlock a range of pages in the vma. * @vma: target vma @@ -168,11 +181,9 @@ static long __mlock_vma_pages_range(struct vm_area_struct *vma, gup_flags |= FOLL_WRITE; /* We don't try to access the guard page of a stack vma */ - if (vma->vm_flags & VM_GROWSDOWN) { - if (start == vma->vm_start) { - start += PAGE_SIZE; - nr_pages--; - } + if (stack_guard_page(vma, start)) { + addr += PAGE_SIZE; + nr_pages--; } while (nr_pages > 0) { -- cgit v0.10.2 From 0e8e50e20c837eeec8323bba7dcd25fe5479194c Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 20 Aug 2010 16:49:40 -0700 Subject: mm: make stack guard page logic use vm_prev pointer Like the mlock() change previously, this makes the stack guard check code use vma->vm_prev to see what the mapping below the current stack is, rather than have to look it up with find_vma(). Also, accept an abutting stack segment, since that happens naturally if you split the stack with mlock or mprotect. Tested-by: Ian Campbell Signed-off-by: Linus Torvalds diff --git a/mm/memory.c b/mm/memory.c index b6e5fd2..2ed2267 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2770,11 +2770,18 @@ static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned lo { address &= PAGE_MASK; if ((vma->vm_flags & VM_GROWSDOWN) && address == vma->vm_start) { - address -= PAGE_SIZE; - if (find_vma(vma->vm_mm, address) != vma) - return -ENOMEM; + struct vm_area_struct *prev = vma->vm_prev; + + /* + * Is there a mapping abutting this one below? + * + * That's only ok if it's the same stack mapping + * that has gotten split.. + */ + if (prev && prev->vm_end == address) + return prev->vm_flags & VM_GROWSDOWN ? 0 : -ENOMEM; - expand_stack(vma, address); + expand_stack(vma, address - PAGE_SIZE); } return 0; } -- cgit v0.10.2 From ddb0c5a689c857bb13a42d9a3f0a7604497b3a29 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Sat, 21 Aug 2010 21:32:41 +0200 Subject: Replace Configure with Enable in description of MAXSMP The "Configure" word tends to make user believe they have to say 'yes' to be able to choose the number of procs/nodes. "Enable" should be unambiguous enough. Signed-off-by: Samuel Thibault Signed-off-by: Linus Torvalds diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index ac7827f..cea0cd9 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -754,11 +754,11 @@ config IOMMU_API def_bool (AMD_IOMMU || DMAR) config MAXSMP - bool "Configure Maximum number of SMP Processors and NUMA Nodes" + bool "Enable Maximum number of SMP Processors and NUMA Nodes" depends on X86_64 && SMP && DEBUG_KERNEL && EXPERIMENTAL select CPUMASK_OFFSTACK ---help--- - Configure maximum number of CPUS and NUMA Nodes for this architecture. + Enable maximum number of CPUS and NUMA Nodes for this architecture. If unsure, say N. config NR_CPUS -- cgit v0.10.2 From e36c886a0f9d624377977fa6cae309cfd7f362fa Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Sat, 21 Aug 2010 13:07:26 -0700 Subject: workqueue: Add basic tracepoints to track workqueue execution With the introduction of the new unified work queue thread pools, we lost one feature: It's no longer possible to know which worker is causing the CPU to wake out of idle. The result is that PowerTOP now reports a lot of "kworker/a:b" instead of more readable results. This patch adds a pair of tracepoints to the new workqueue code, similar in style to the timer/hrtimer tracepoints. With this pair of tracepoints, the next PowerTOP can correctly report which work item caused the wakeup (and how long it took): Interrupt (43) i915 time 3.51ms wakeups 141 Work ieee80211_iface_work time 0.81ms wakeups 29 Work do_dbs_timer time 0.55ms wakeups 24 Process Xorg time 21.36ms wakeups 4 Timer sched_rt_period_timer time 0.01ms wakeups 1 Signed-off-by: Arjan van de Ven Signed-off-by: Linus Torvalds diff --git a/include/trace/events/workqueue.h b/include/trace/events/workqueue.h new file mode 100644 index 0000000..49682d7 --- /dev/null +++ b/include/trace/events/workqueue.h @@ -0,0 +1,62 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM workqueue + +#if !defined(_TRACE_WORKQUEUE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_WORKQUEUE_H + +#include +#include + +/** + * workqueue_execute_start - called immediately before the workqueue callback + * @work: pointer to struct work_struct + * + * Allows to track workqueue execution. + */ +TRACE_EVENT(workqueue_execute_start, + + TP_PROTO(struct work_struct *work), + + TP_ARGS(work), + + TP_STRUCT__entry( + __field( void *, work ) + __field( void *, function) + ), + + TP_fast_assign( + __entry->work = work; + __entry->function = work->func; + ), + + TP_printk("work struct %p: function %pf", __entry->work, __entry->function) +); + +/** + * workqueue_execute_end - called immediately before the workqueue callback + * @work: pointer to struct work_struct + * + * Allows to track workqueue execution. + */ +TRACE_EVENT(workqueue_execute_end, + + TP_PROTO(struct work_struct *work), + + TP_ARGS(work), + + TP_STRUCT__entry( + __field( void *, work ) + ), + + TP_fast_assign( + __entry->work = work; + ), + + TP_printk("work struct %p", __entry->work) +); + + +#endif /* _TRACE_WORKQUEUE_H */ + +/* This part must be outside protection */ +#include diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 2994a0e..8bd600c 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -35,6 +35,9 @@ #include #include +#define CREATE_TRACE_POINTS +#include + #include "workqueue_sched.h" enum { @@ -1790,7 +1793,13 @@ static void process_one_work(struct worker *worker, struct work_struct *work) work_clear_pending(work); lock_map_acquire(&cwq->wq->lockdep_map); lock_map_acquire(&lockdep_map); + trace_workqueue_execute_start(work); f(work); + /* + * While we must be careful to not use "work" after this, the trace + * point will only record its address. + */ + trace_workqueue_execute_end(work); lock_map_release(&lockdep_map); lock_map_release(&cwq->wq->lockdep_map); -- cgit v0.10.2 From 9d0498a2bf7455159b317f19531a3e5db2ecc9c4 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 18 Aug 2010 13:20:54 -0700 Subject: drm/i915: wait for actual vblank, not just 20ms Waiting for a hard coded 20ms isn't always enough to make sure a vblank period has actually occurred, so add code to make sure we really have passed through a vblank period (or that the pipe is off when disabling). This prevents problems with mode setting and link training, and seems to fix a bug like https://bugs.freedesktop.org/show_bug.cgi?id=29278, but on an HP 8440p instead. Hopefully also fixes https://bugs.freedesktop.org/show_bug.cgi?id=29141. Signed-off-by: Jesse Barnes Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a63e9a1..67e3ec1 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2081,6 +2081,7 @@ #define PIPE_DITHER_TYPE_ST01 (1 << 2) /* Pipe A */ #define PIPEADSL 0x70000 +#define DSL_LINEMASK 0x00000fff #define PIPEACONF 0x70008 #define PIPEACONF_ENABLE (1<<31) #define PIPEACONF_DISABLE 0 diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index c43176d..eb31fdf 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -328,7 +328,7 @@ intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER); /* Wait for next Vblank to substitue * border color for Color info */ - intel_wait_for_vblank(dev); + intel_wait_for_vblank(dev, pipe); st00 = I915_READ8(VGA_MSR_WRITE); status = ((st00 & (1 << 4)) != 0) ? connector_status_connected : diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 14c45b1..bdea946 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -977,14 +977,54 @@ intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc, return true; } -void -intel_wait_for_vblank(struct drm_device *dev) +/** + * intel_wait_for_vblank - wait for vblank on a given pipe + * @dev: drm device + * @pipe: pipe to wait for + * + * Wait for vblank to occur on a given pipe. Needed for various bits of + * mode setting code. + */ +void intel_wait_for_vblank(struct drm_device *dev, int pipe) { - /* Wait for 20ms, i.e. one cycle at 50hz. */ - if (in_dbg_master()) - mdelay(20); /* The kernel debugger cannot call msleep() */ - else - msleep(20); + struct drm_i915_private *dev_priv = dev->dev_private; + int pipestat_reg = (pipe == 0 ? PIPEASTAT : PIPEBSTAT); + + /* Wait for vblank interrupt bit to set */ + if (wait_for((I915_READ(pipestat_reg) & + PIPE_VBLANK_INTERRUPT_STATUS) == 0, + 50, 0)) + DRM_DEBUG_KMS("vblank wait timed out\n"); +} + +/** + * intel_wait_for_vblank_off - wait for vblank after disabling a pipe + * @dev: drm device + * @pipe: pipe to wait for + * + * After disabling a pipe, we can't wait for vblank in the usual way, + * spinning on the vblank interrupt status bit, since we won't actually + * see an interrupt when the pipe is disabled. + * + * So this function waits for the display line value to settle (it + * usually ends up stopping at the start of the next frame). + */ +void intel_wait_for_vblank_off(struct drm_device *dev, int pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int pipedsl_reg = (pipe == 0 ? PIPEADSL : PIPEBDSL); + unsigned long timeout = jiffies + msecs_to_jiffies(100); + u32 last_line; + + /* Wait for the display line to settle */ + do { + last_line = I915_READ(pipedsl_reg) & DSL_LINEMASK; + mdelay(5); + } while (((I915_READ(pipedsl_reg) & DSL_LINEMASK) != last_line) && + time_after(timeout, jiffies)); + + if (time_after(jiffies, timeout)) + DRM_DEBUG_KMS("vblank wait timed out\n"); } /* Parameters have changed, update FBC info */ @@ -1057,8 +1097,6 @@ void i8xx_disable_fbc(struct drm_device *dev) return; } - intel_wait_for_vblank(dev); - DRM_DEBUG_KMS("disabled FBC\n"); } @@ -1115,7 +1153,6 @@ void g4x_disable_fbc(struct drm_device *dev) dpfc_ctl = I915_READ(DPFC_CONTROL); dpfc_ctl &= ~DPFC_CTL_EN; I915_WRITE(DPFC_CONTROL, dpfc_ctl); - intel_wait_for_vblank(dev); DRM_DEBUG_KMS("disabled FBC\n"); } @@ -1176,7 +1213,6 @@ void ironlake_disable_fbc(struct drm_device *dev) dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); dpfc_ctl &= ~DPFC_CTL_EN; I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl); - intel_wait_for_vblank(dev); DRM_DEBUG_KMS("disabled FBC\n"); } @@ -1475,7 +1511,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, if ((IS_I965G(dev) || plane == 0)) intel_update_fbc(crtc, &crtc->mode); - intel_wait_for_vblank(dev); + intel_wait_for_vblank(dev, intel_crtc->pipe); intel_increase_pllclock(crtc, true); return 0; @@ -1593,7 +1629,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, if ((IS_I965G(dev) || plane == 0)) intel_update_fbc(crtc, &crtc->mode); - intel_wait_for_vblank(dev); + intel_wait_for_vblank(dev, pipe); if (old_fb) { intel_fb = to_intel_framebuffer(old_fb); @@ -2343,10 +2379,8 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) I915_READ(dspbase_reg); } - if (!IS_I9XX(dev)) { - /* Wait for vblank for the disable to take effect */ - intel_wait_for_vblank(dev); - } + /* Wait for vblank for the disable to take effect */ + intel_wait_for_vblank_off(dev, pipe); /* Don't disable pipe A or pipe A PLLs if needed */ if (pipeconf_reg == PIPEACONF && @@ -2361,7 +2395,7 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) } /* Wait for vblank for the disable to take effect. */ - intel_wait_for_vblank(dev); + intel_wait_for_vblank_off(dev, pipe); temp = I915_READ(dpll_reg); if ((temp & DPLL_VCO_ENABLE) != 0) { @@ -4096,7 +4130,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(pipeconf_reg, pipeconf); I915_READ(pipeconf_reg); - intel_wait_for_vblank(dev); + intel_wait_for_vblank(dev, pipe); if (IS_IRONLAKE(dev)) { /* enable address swizzle for tiling buffer */ @@ -4508,7 +4542,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder, encoder_funcs->commit(encoder); } /* let the connector get through one full cycle before testing */ - intel_wait_for_vblank(dev); + intel_wait_for_vblank(dev, intel_crtc->pipe); return crtc; } @@ -4713,7 +4747,7 @@ static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule) dpll &= ~DISPLAY_RATE_SELECT_FPA1; I915_WRITE(dpll_reg, dpll); dpll = I915_READ(dpll_reg); - intel_wait_for_vblank(dev); + 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"); @@ -4757,7 +4791,7 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc) dpll |= DISPLAY_RATE_SELECT_FPA1; I915_WRITE(dpll_reg, dpll); dpll = I915_READ(dpll_reg); - intel_wait_for_vblank(dev); + 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"); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index caaaa8f..9caccd0 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1145,12 +1145,13 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, { struct drm_device *dev = intel_dp->base.enc.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.enc.crtc); int ret; I915_WRITE(intel_dp->output_reg, dp_reg_value); POSTING_READ(intel_dp->output_reg); if (first) - intel_wait_for_vblank(dev); + intel_wait_for_vblank(dev, intel_crtc->pipe); intel_dp_aux_native_write_1(intel_dp, DP_TRAINING_PATTERN_SET, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 6ba56e1..0e92aa0 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -219,7 +219,8 @@ extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, struct drm_crtc *crtc); int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern void intel_wait_for_vblank(struct drm_device *dev); +extern void intel_wait_for_vblank_off(struct drm_device *dev, int pipe); +extern void intel_wait_for_vblank(struct drm_device *dev, int pipe); extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe); extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder, struct drm_connector *connector, diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 5c765bb..093e914 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1218,6 +1218,7 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); u32 temp; if (mode != DRM_MODE_DPMS_ON) { @@ -1240,7 +1241,7 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) if ((temp & SDVO_ENABLE) == 0) intel_sdvo_write_sdvox(intel_sdvo, temp | SDVO_ENABLE); for (i = 0; i < 2; i++) - intel_wait_for_vblank(dev); + intel_wait_for_vblank(dev, intel_crtc->pipe); status = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2); /* Warn if the device reported failure to sync. diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 1bd6e87..d2029ef 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1158,11 +1158,11 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, /* Wait for vblank for the disable to take effect */ if (!IS_I9XX(dev)) - intel_wait_for_vblank(dev); + intel_wait_for_vblank(dev, intel_crtc->pipe); I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE); /* Wait for vblank for the disable to take effect. */ - intel_wait_for_vblank(dev); + intel_wait_for_vblank(dev, intel_crtc->pipe); /* Filter ctl must be set before TV_WIN_SIZE */ I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE); @@ -1231,6 +1231,7 @@ intel_tv_detect_type (struct intel_tv *intel_tv) struct drm_encoder *encoder = &intel_tv->base.enc; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); unsigned long irqflags; u32 tv_ctl, save_tv_ctl; u32 tv_dac, save_tv_dac; @@ -1267,11 +1268,11 @@ intel_tv_detect_type (struct intel_tv *intel_tv) DAC_C_0_7_V); I915_WRITE(TV_CTL, tv_ctl); I915_WRITE(TV_DAC, tv_dac); - intel_wait_for_vblank(dev); + intel_wait_for_vblank(dev, intel_crtc->pipe); tv_dac = I915_READ(TV_DAC); I915_WRITE(TV_DAC, save_tv_dac); I915_WRITE(TV_CTL, save_tv_ctl); - intel_wait_for_vblank(dev); + intel_wait_for_vblank(dev, intel_crtc->pipe); /* * A B C * 0 1 1 Composite -- cgit v0.10.2 From d5dd96cb280993a6096b42ab082f9cfd9c7ae0bd Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 4 Aug 2010 15:52:19 +1000 Subject: i915: disable DAC on Ironlake also when doing CRT load detection. Like on Sandybridge, disabling the DAC here when doing CRT load detect avoids forever hangs waiting on the hardware. test procedure on HP 2740p: boot with no VGA plugged in, start X, plug in VGA monitor (1280x1024) chvt 3 machine hangs waiting forever. Signed-off-by: Dave Airlie Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index eb31fdf..4b77351 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -160,19 +160,20 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) struct drm_i915_private *dev_priv = dev->dev_private; u32 adpa, temp; bool ret; + bool turn_off_dac = false; temp = adpa = I915_READ(PCH_ADPA); - if (HAS_PCH_CPT(dev)) { - /* Disable DAC before force detect */ - I915_WRITE(PCH_ADPA, adpa & ~ADPA_DAC_ENABLE); - (void)I915_READ(PCH_ADPA); - } else { - adpa &= ~ADPA_CRT_HOTPLUG_MASK; - /* disable HPD first */ - I915_WRITE(PCH_ADPA, adpa); - (void)I915_READ(PCH_ADPA); - } + if (HAS_PCH_SPLIT(dev)) + turn_off_dac = true; + + adpa &= ~ADPA_CRT_HOTPLUG_MASK; + if (turn_off_dac) + adpa &= ~ADPA_DAC_ENABLE; + + /* disable HPD first */ + I915_WRITE(PCH_ADPA, adpa); + (void)I915_READ(PCH_ADPA); adpa |= (ADPA_CRT_HOTPLUG_PERIOD_128 | ADPA_CRT_HOTPLUG_WARMUP_10MS | @@ -189,7 +190,7 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) 1000, 1)) DRM_ERROR("timed out waiting for FORCE_TRIGGER"); - if (HAS_PCH_CPT(dev)) { + if (turn_off_dac) { I915_WRITE(PCH_ADPA, temp); (void)I915_READ(PCH_ADPA); } -- cgit v0.10.2 From 72bcb2690927f04c0479cd0d83825f09f3bf4d4f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 14 Aug 2010 14:41:22 +0100 Subject: drm/i915/suspend: Flush register writes before busy-waiting. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 6e20252..05acc26 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -395,16 +395,20 @@ static void i915_restore_modeset_reg(struct drm_device *dev) if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) { I915_WRITE(dpll_a_reg, dev_priv->saveDPLL_A & ~DPLL_VCO_ENABLE); - DRM_UDELAY(150); + POSTING_READ(dpll_a_reg); + udelay(150); } I915_WRITE(fpa0_reg, dev_priv->saveFPA0); I915_WRITE(fpa1_reg, dev_priv->saveFPA1); /* Actually enable it */ I915_WRITE(dpll_a_reg, dev_priv->saveDPLL_A); - DRM_UDELAY(150); - if (IS_I965G(dev) && !IS_IRONLAKE(dev)) + POSTING_READ(dpll_a_reg); + udelay(150); + if (IS_I965G(dev) && !IS_IRONLAKE(dev)) { I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD); - DRM_UDELAY(150); + POSTING_READ(DPLL_A_MD); + } + udelay(150); /* Restore mode */ I915_WRITE(HTOTAL_A, dev_priv->saveHTOTAL_A); @@ -460,16 +464,20 @@ static void i915_restore_modeset_reg(struct drm_device *dev) if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) { I915_WRITE(dpll_b_reg, dev_priv->saveDPLL_B & ~DPLL_VCO_ENABLE); - DRM_UDELAY(150); + POSTING_READ(dpll_b_reg); + udelay(150); } I915_WRITE(fpb0_reg, dev_priv->saveFPB0); I915_WRITE(fpb1_reg, dev_priv->saveFPB1); /* Actually enable it */ I915_WRITE(dpll_b_reg, dev_priv->saveDPLL_B); - DRM_UDELAY(150); - if (IS_I965G(dev) && !IS_IRONLAKE(dev)) + POSTING_READ(dpll_b_reg); + udelay(150); + if (IS_I965G(dev) && !IS_IRONLAKE(dev)) { I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD); - DRM_UDELAY(150); + POSTING_READ(DPLL_B_MD); + } + udelay(150); /* Restore mode */ I915_WRITE(HTOTAL_B, dev_priv->saveHTOTAL_B); @@ -730,7 +738,8 @@ void i915_restore_display(struct drm_device *dev) I915_WRITE(VGA0, dev_priv->saveVGA0); I915_WRITE(VGA1, dev_priv->saveVGA1); I915_WRITE(VGA_PD, dev_priv->saveVGA_PD); - DRM_UDELAY(150); + POSTING_READ(VGA_PD); + udelay(150); i915_restore_vga(dev); } -- cgit v0.10.2 From 90eb77baaea35c591bd324b31e9eac032bd603c9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 14 Aug 2010 14:41:23 +0100 Subject: drm/i915/suspend: s/IS_IRONLAKE/HAS_PCH_SPLIT/ For the shared paths on the next generation chipsets. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 05acc26..2c6b98f 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -34,7 +34,7 @@ static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe) struct drm_i915_private *dev_priv = dev->dev_private; u32 dpll_reg; - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { dpll_reg = (pipe == PIPE_A) ? PCH_DPLL_A: PCH_DPLL_B; } else { dpll_reg = (pipe == PIPE_A) ? DPLL_A: DPLL_B; @@ -53,7 +53,7 @@ static void i915_save_palette(struct drm_device *dev, enum pipe pipe) if (!i915_pipe_enabled(dev, pipe)) return; - if (IS_IRONLAKE(dev)) + if (HAS_PCH_SPLIT(dev)) reg = (pipe == PIPE_A) ? LGC_PALETTE_A : LGC_PALETTE_B; if (pipe == PIPE_A) @@ -75,7 +75,7 @@ static void i915_restore_palette(struct drm_device *dev, enum pipe pipe) if (!i915_pipe_enabled(dev, pipe)) return; - if (IS_IRONLAKE(dev)) + if (HAS_PCH_SPLIT(dev)) reg = (pipe == PIPE_A) ? LGC_PALETTE_A : LGC_PALETTE_B; if (pipe == PIPE_A) @@ -239,7 +239,7 @@ static void i915_save_modeset_reg(struct drm_device *dev) if (drm_core_check_feature(dev, DRIVER_MODESET)) return; - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { dev_priv->savePCH_DREF_CONTROL = I915_READ(PCH_DREF_CONTROL); dev_priv->saveDISP_ARB_CTL = I915_READ(DISP_ARB_CTL); } @@ -247,7 +247,7 @@ static void i915_save_modeset_reg(struct drm_device *dev) /* Pipe & plane A info */ dev_priv->savePIPEACONF = I915_READ(PIPEACONF); dev_priv->savePIPEASRC = I915_READ(PIPEASRC); - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { dev_priv->saveFPA0 = I915_READ(PCH_FPA0); dev_priv->saveFPA1 = I915_READ(PCH_FPA1); dev_priv->saveDPLL_A = I915_READ(PCH_DPLL_A); @@ -256,7 +256,7 @@ static void i915_save_modeset_reg(struct drm_device *dev) dev_priv->saveFPA1 = I915_READ(FPA1); dev_priv->saveDPLL_A = I915_READ(DPLL_A); } - if (IS_I965G(dev) && !IS_IRONLAKE(dev)) + if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) dev_priv->saveDPLL_A_MD = I915_READ(DPLL_A_MD); dev_priv->saveHTOTAL_A = I915_READ(HTOTAL_A); dev_priv->saveHBLANK_A = I915_READ(HBLANK_A); @@ -264,10 +264,10 @@ static void i915_save_modeset_reg(struct drm_device *dev) dev_priv->saveVTOTAL_A = I915_READ(VTOTAL_A); dev_priv->saveVBLANK_A = I915_READ(VBLANK_A); dev_priv->saveVSYNC_A = I915_READ(VSYNC_A); - if (!IS_IRONLAKE(dev)) + if (!HAS_PCH_SPLIT(dev)) dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A); - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { dev_priv->savePIPEA_DATA_M1 = I915_READ(PIPEA_DATA_M1); dev_priv->savePIPEA_DATA_N1 = I915_READ(PIPEA_DATA_N1); dev_priv->savePIPEA_LINK_M1 = I915_READ(PIPEA_LINK_M1); @@ -304,7 +304,7 @@ static void i915_save_modeset_reg(struct drm_device *dev) /* Pipe & plane B info */ dev_priv->savePIPEBCONF = I915_READ(PIPEBCONF); dev_priv->savePIPEBSRC = I915_READ(PIPEBSRC); - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { dev_priv->saveFPB0 = I915_READ(PCH_FPB0); dev_priv->saveFPB1 = I915_READ(PCH_FPB1); dev_priv->saveDPLL_B = I915_READ(PCH_DPLL_B); @@ -313,7 +313,7 @@ static void i915_save_modeset_reg(struct drm_device *dev) dev_priv->saveFPB1 = I915_READ(FPB1); dev_priv->saveDPLL_B = I915_READ(DPLL_B); } - if (IS_I965G(dev) && !IS_IRONLAKE(dev)) + if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) dev_priv->saveDPLL_B_MD = I915_READ(DPLL_B_MD); dev_priv->saveHTOTAL_B = I915_READ(HTOTAL_B); dev_priv->saveHBLANK_B = I915_READ(HBLANK_B); @@ -321,10 +321,10 @@ static void i915_save_modeset_reg(struct drm_device *dev) dev_priv->saveVTOTAL_B = I915_READ(VTOTAL_B); dev_priv->saveVBLANK_B = I915_READ(VBLANK_B); dev_priv->saveVSYNC_B = I915_READ(VSYNC_B); - if (!IS_IRONLAKE(dev)) + if (!HAS_PCH_SPLIT(dev)) dev_priv->saveBCLRPAT_B = I915_READ(BCLRPAT_B); - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { dev_priv->savePIPEB_DATA_M1 = I915_READ(PIPEB_DATA_M1); dev_priv->savePIPEB_DATA_N1 = I915_READ(PIPEB_DATA_N1); dev_priv->savePIPEB_LINK_M1 = I915_READ(PIPEB_LINK_M1); @@ -369,7 +369,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev) if (drm_core_check_feature(dev, DRIVER_MODESET)) return; - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { dpll_a_reg = PCH_DPLL_A; dpll_b_reg = PCH_DPLL_B; fpa0_reg = PCH_FPA0; @@ -385,7 +385,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev) fpb1_reg = FPB1; } - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { I915_WRITE(PCH_DREF_CONTROL, dev_priv->savePCH_DREF_CONTROL); I915_WRITE(DISP_ARB_CTL, dev_priv->saveDISP_ARB_CTL); } @@ -404,7 +404,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev) I915_WRITE(dpll_a_reg, dev_priv->saveDPLL_A); POSTING_READ(dpll_a_reg); udelay(150); - if (IS_I965G(dev) && !IS_IRONLAKE(dev)) { + if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) { I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD); POSTING_READ(DPLL_A_MD); } @@ -417,10 +417,10 @@ static void i915_restore_modeset_reg(struct drm_device *dev) I915_WRITE(VTOTAL_A, dev_priv->saveVTOTAL_A); I915_WRITE(VBLANK_A, dev_priv->saveVBLANK_A); I915_WRITE(VSYNC_A, dev_priv->saveVSYNC_A); - if (!IS_IRONLAKE(dev)) + if (!HAS_PCH_SPLIT(dev)) I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A); - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { I915_WRITE(PIPEA_DATA_M1, dev_priv->savePIPEA_DATA_M1); I915_WRITE(PIPEA_DATA_N1, dev_priv->savePIPEA_DATA_N1); I915_WRITE(PIPEA_LINK_M1, dev_priv->savePIPEA_LINK_M1); @@ -473,7 +473,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev) I915_WRITE(dpll_b_reg, dev_priv->saveDPLL_B); POSTING_READ(dpll_b_reg); udelay(150); - if (IS_I965G(dev) && !IS_IRONLAKE(dev)) { + if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) { I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD); POSTING_READ(DPLL_B_MD); } @@ -486,10 +486,10 @@ static void i915_restore_modeset_reg(struct drm_device *dev) I915_WRITE(VTOTAL_B, dev_priv->saveVTOTAL_B); I915_WRITE(VBLANK_B, dev_priv->saveVBLANK_B); I915_WRITE(VSYNC_B, dev_priv->saveVSYNC_B); - if (!IS_IRONLAKE(dev)) + if (!HAS_PCH_SPLIT(dev)) I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B); - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { I915_WRITE(PIPEB_DATA_M1, dev_priv->savePIPEB_DATA_M1); I915_WRITE(PIPEB_DATA_N1, dev_priv->savePIPEB_DATA_N1); I915_WRITE(PIPEB_LINK_M1, dev_priv->savePIPEB_LINK_M1); @@ -554,14 +554,14 @@ void i915_save_display(struct drm_device *dev) dev_priv->saveCURSIZE = I915_READ(CURSIZE); /* CRT state */ - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { dev_priv->saveADPA = I915_READ(PCH_ADPA); } else { dev_priv->saveADPA = I915_READ(ADPA); } /* LVDS state */ - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { dev_priv->savePP_CONTROL = I915_READ(PCH_PP_CONTROL); dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_PCH_CTL1); dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_PCH_CTL2); @@ -579,10 +579,10 @@ void i915_save_display(struct drm_device *dev) dev_priv->saveLVDS = I915_READ(LVDS); } - if (!IS_I830(dev) && !IS_845G(dev) && !IS_IRONLAKE(dev)) + if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev)) dev_priv->savePFIT_CONTROL = I915_READ(PFIT_CONTROL); - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { dev_priv->savePP_ON_DELAYS = I915_READ(PCH_PP_ON_DELAYS); dev_priv->savePP_OFF_DELAYS = I915_READ(PCH_PP_OFF_DELAYS); dev_priv->savePP_DIVISOR = I915_READ(PCH_PP_DIVISOR); @@ -610,7 +610,7 @@ void i915_save_display(struct drm_device *dev) /* Only save FBC state on the platform that supports FBC */ if (I915_HAS_FBC(dev)) { - if (IS_IRONLAKE_M(dev)) { + if (HAS_PCH_SPLIT(dev)) { dev_priv->saveDPFC_CB_BASE = I915_READ(ILK_DPFC_CB_BASE); } else if (IS_GM45(dev)) { dev_priv->saveDPFC_CB_BASE = I915_READ(DPFC_CB_BASE); @@ -626,7 +626,7 @@ void i915_save_display(struct drm_device *dev) dev_priv->saveVGA0 = I915_READ(VGA0); dev_priv->saveVGA1 = I915_READ(VGA1); dev_priv->saveVGA_PD = I915_READ(VGA_PD); - if (IS_IRONLAKE(dev)) + if (HAS_PCH_SPLIT(dev)) dev_priv->saveVGACNTRL = I915_READ(CPU_VGACNTRL); else dev_priv->saveVGACNTRL = I915_READ(VGACNTRL); @@ -668,24 +668,24 @@ void i915_restore_display(struct drm_device *dev) I915_WRITE(CURSIZE, dev_priv->saveCURSIZE); /* CRT state */ - if (IS_IRONLAKE(dev)) + if (HAS_PCH_SPLIT(dev)) I915_WRITE(PCH_ADPA, dev_priv->saveADPA); else I915_WRITE(ADPA, dev_priv->saveADPA); /* LVDS state */ - if (IS_I965G(dev) && !IS_IRONLAKE(dev)) + if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) I915_WRITE(BLC_PWM_CTL2, dev_priv->saveBLC_PWM_CTL2); - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { I915_WRITE(PCH_LVDS, dev_priv->saveLVDS); } else if (IS_MOBILE(dev) && !IS_I830(dev)) I915_WRITE(LVDS, dev_priv->saveLVDS); - if (!IS_I830(dev) && !IS_845G(dev) && !IS_IRONLAKE(dev)) + if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev)) I915_WRITE(PFIT_CONTROL, dev_priv->savePFIT_CONTROL); - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { I915_WRITE(BLC_PWM_PCH_CTL1, dev_priv->saveBLC_PWM_CTL); I915_WRITE(BLC_PWM_PCH_CTL2, dev_priv->saveBLC_PWM_CTL2); I915_WRITE(BLC_PWM_CPU_CTL, dev_priv->saveBLC_CPU_PWM_CTL); @@ -716,7 +716,7 @@ void i915_restore_display(struct drm_device *dev) /* only restore FBC info on the platform that supports FBC*/ if (I915_HAS_FBC(dev)) { - if (IS_IRONLAKE_M(dev)) { + if (HAS_PCH_SPLIT(dev)) { ironlake_disable_fbc(dev); I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE); } else if (IS_GM45(dev)) { @@ -731,7 +731,7 @@ void i915_restore_display(struct drm_device *dev) } } /* VGA state */ - if (IS_IRONLAKE(dev)) + if (HAS_PCH_SPLIT(dev)) I915_WRITE(CPU_VGACNTRL, dev_priv->saveVGACNTRL); else I915_WRITE(VGACNTRL, dev_priv->saveVGACNTRL); @@ -757,7 +757,7 @@ int i915_save_state(struct drm_device *dev) i915_save_display(dev); /* Interrupt state */ - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { dev_priv->saveDEIER = I915_READ(DEIER); dev_priv->saveDEIMR = I915_READ(DEIMR); dev_priv->saveGTIER = I915_READ(GTIER); @@ -771,7 +771,7 @@ int i915_save_state(struct drm_device *dev) dev_priv->saveIMR = I915_READ(IMR); } - if (IS_IRONLAKE_M(dev)) + if (HAS_PCH_SPLIT(dev)) ironlake_disable_drps(dev); /* Cache mode state */ @@ -829,7 +829,7 @@ int i915_restore_state(struct drm_device *dev) i915_restore_display(dev); /* Interrupt state */ - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { I915_WRITE(DEIER, dev_priv->saveDEIER); I915_WRITE(DEIMR, dev_priv->saveDEIMR); I915_WRITE(GTIER, dev_priv->saveGTIER); @@ -844,7 +844,7 @@ int i915_restore_state(struct drm_device *dev) /* Clock gating state */ intel_init_clock_gating(dev); - if (IS_IRONLAKE_M(dev)) + if (HAS_PCH_SPLIT(dev)) ironlake_enable_drps(dev); /* Cache mode state */ -- cgit v0.10.2 From 156dadc180a1bd3a25d644ee6c361afc465ccd0e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 15 Aug 2010 10:52:34 +0100 Subject: drm/i915: Remove the conflicting BUG_ON() We now attempt to free "active" objects following a GPU hang as either the GPU will be reset or the hang is permenant. In either case, the GPU writes will not be flushed to main memory and it should be safe to return that memory back to the system. The BUG_ON(active) is thus overkill and can erroneously fire after a EIO. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b4b25e1..994e9f2 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1979,8 +1979,6 @@ i915_gem_object_unbind(struct drm_gem_object *obj) * cause memory corruption through use-after-free. */ - BUG_ON(obj_priv->active); - /* release the fence reg _after_ flushing */ if (obj_priv->fence_reg != I915_FENCE_REG_NONE) i915_gem_clear_fence_reg(obj); -- cgit v0.10.2 From 877fdacf8291d7627f339885b5ae52c2f6061734 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Thu, 19 Aug 2010 09:46:13 +0800 Subject: agp/intel: set 40-bit dma mask on Sandybridge Signed-off-by: Zhenyu Wang Signed-off-by: Eric Anholt diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index ddf5def..ab19039 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -825,7 +825,8 @@ static const struct intel_driver_description { static int __devinit intel_gmch_probe(struct pci_dev *pdev, struct agp_bridge_data *bridge) { - int i; + int i, mask; + bridge->driver = NULL; for (i = 0; intel_agp_chipsets[i].name != NULL; i++) { @@ -845,14 +846,19 @@ static int __devinit intel_gmch_probe(struct pci_dev *pdev, dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name); - if (bridge->driver->mask_memory == intel_i965_mask_memory) { - if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(36))) - dev_err(&intel_private.pcidev->dev, - "set gfx device dma mask 36bit failed!\n"); - else - pci_set_consistent_dma_mask(intel_private.pcidev, - DMA_BIT_MASK(36)); - } + if (bridge->driver->mask_memory == intel_gen6_mask_memory) + mask = 40; + else if (bridge->driver->mask_memory == intel_i965_mask_memory) + mask = 36; + else + mask = 32; + + if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask))) + dev_err(&intel_private.pcidev->dev, + "set gfx device dma mask %d-bit failed!\n", mask); + else + pci_set_consistent_dma_mask(intel_private.pcidev, + DMA_BIT_MASK(mask)); return 1; } -- cgit v0.10.2 From 3fdef0205e69b80c4219f14b834cb85eb719039f Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Thu, 19 Aug 2010 09:46:15 +0800 Subject: drm/i915: fix render pipe control notify on sandybridge This one is missed in last pipe control fix for sandybridge, that really unmask interrupt bit for notify in render engine IMR. Signed-off-by: Zhenyu Wang Signed-off-by: Eric Anholt diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 69a36fc..16861b8 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1381,12 +1381,17 @@ static int ironlake_irq_postinstall(struct drm_device *dev) I915_WRITE(DEIER, dev_priv->de_irq_enable_reg); (void) I915_READ(DEIER); - /* user interrupt should be enabled, but masked initial */ + /* Gen6 only needs render pipe_control now */ + if (IS_GEN6(dev)) + render_mask = GT_PIPE_NOTIFY; + dev_priv->gt_irq_mask_reg = ~render_mask; dev_priv->gt_irq_enable_reg = render_mask; I915_WRITE(GTIIR, I915_READ(GTIIR)); I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg); + if (IS_GEN6(dev)) + I915_WRITE(GEN6_RENDER_IMR, ~GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT); I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg); (void) I915_READ(GTIER); -- cgit v0.10.2 From 4fefe435626758b14e6c05d2a5f8d71a997c0ad6 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Thu, 19 Aug 2010 09:46:16 +0800 Subject: drm/i915,intel_agp: Add support for Sandybridge D0 Signed-off-by: Zhenyu Wang Signed-off-by: Eric Anholt diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index ab19039..710af89 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -819,6 +819,8 @@ static const struct intel_driver_description { "Sandybridge", NULL, &intel_gen6_driver }, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG, "Sandybridge", NULL, &intel_gen6_driver }, + { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_D0_IG, + "Sandybridge", NULL, &intel_gen6_driver }, { 0, 0, NULL, NULL, NULL } }; diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h index c05e3e5..08d4753 100644 --- a/drivers/char/agp/intel-agp.h +++ b/drivers/char/agp/intel-agp.h @@ -204,6 +204,7 @@ #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG 0x0102 #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB 0x0104 #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG 0x0106 +#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_D0_IG 0x0126 /* cover 915 and 945 variants */ #define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \ diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 5044f65..00befce 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -181,6 +181,7 @@ static const struct pci_device_id pciidlist[] = { /* aka */ INTEL_VGA_DEVICE(0x0046, &intel_ironlake_m_info), INTEL_VGA_DEVICE(0x0102, &intel_sandybridge_d_info), INTEL_VGA_DEVICE(0x0106, &intel_sandybridge_m_info), + INTEL_VGA_DEVICE(0x0126, &intel_sandybridge_m_info), {0, 0, 0} }; -- cgit v0.10.2 From 4dfe947e74a1de3eb638cc36d51bf56d6609057b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 23 Aug 2010 08:27:47 +1000 Subject: drm/radeon: fix passing wrong type to gem object create. We are passing a ttm type when we want to pass true/false. Reported-by: Dr. David Alan Gilbert Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index dc1634b..11f4f30 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -118,7 +118,7 @@ static int radeonfb_create_pinned_object(struct radeon_fbdev *rfbdev, aligned_size = ALIGN(size, PAGE_SIZE); ret = radeon_gem_object_create(rdev, aligned_size, 0, RADEON_GEM_DOMAIN_VRAM, - false, ttm_bo_type_kernel, + false, true, &gobj); if (ret) { printk(KERN_ERR "failed to allocate framebuffer (%d)\n", -- cgit v0.10.2 From 4b80d954a7e54c13a5063af18d01719ad6a0daf3 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 20 Aug 2010 12:47:54 -0400 Subject: drm/radeon/kms: fix sideport detection on newer rs880 boards The meaning of ucMemoryType changed on recent boards, however, ulBootUpSidePortClock should be set properly across all boards. Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index b015915..6114198 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1181,7 +1181,7 @@ bool radeon_atombios_sideport_present(struct radeon_device *rdev) return true; break; case 2: - if (igp_info->info_2.ucMemoryType & 0x0f) + if (igp_info->info_2.ulBootUpSidePortClock) return true; break; default: -- cgit v0.10.2 From 039ed2d9a24b3c4e272439b1551762fcb77c188a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 20 Aug 2010 11:57:19 -0400 Subject: drm/radeon/kms: try to detect tv vs monitor for underscan When enabling underscan for hdmi monitors, attempt to detect whether we are driving a TV or a monitor. The should hopefully prevent underscan from being enabled on monitors attached via hdmi that do not overscan the image. Only enable underscan if the mode is a common hdtv mode (480p, 720p, etc.). Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 5764f4d..6dd434a 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -1094,6 +1094,18 @@ void radeon_modeset_fini(struct radeon_device *rdev) radeon_i2c_fini(rdev); } +static bool is_hdtv_mode(struct drm_display_mode *mode) +{ + /* try and guess if this is a tv or a monitor */ + if ((mode->vdisplay == 480 && mode->hdisplay == 720) || /* 480p */ + (mode->vdisplay == 576) || /* 576p */ + (mode->vdisplay == 720) || /* 720p */ + (mode->vdisplay == 1080)) /* 1080p */ + return true; + else + return false; +} + bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -1141,7 +1153,8 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, if (ASIC_IS_AVIVO(rdev) && ((radeon_encoder->underscan_type == UNDERSCAN_ON) || ((radeon_encoder->underscan_type == UNDERSCAN_AUTO) && - drm_detect_hdmi_monitor(radeon_connector->edid)))) { + drm_detect_hdmi_monitor(radeon_connector->edid) && + is_hdtv_mode(mode)))) { radeon_crtc->h_border = (mode->hdisplay >> 5) + 16; radeon_crtc->v_border = (mode->vdisplay >> 5) + 16; radeon_crtc->rmx_type = RMX_FULL; -- cgit v0.10.2 From 0537398b211b4f040564beec458e23571042d335 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 17 Aug 2010 00:35:45 -0400 Subject: drm/radeon/kms: fix typo in radeon_compute_pll_gain Looks like this got copied from the ddx wrong. Cc: Benjamin Herrenschmidt Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index 989df51..305049a 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -272,7 +272,7 @@ static uint8_t radeon_compute_pll_gain(uint16_t ref_freq, uint16_t ref_div, if (!ref_div) return 1; - vcoFreq = ((unsigned)ref_freq & fb_div) / ref_div; + vcoFreq = ((unsigned)ref_freq * fb_div) / ref_div; /* * This is horribly crude: the VCO frequency range is divided into -- cgit v0.10.2 From b6dd08652e2b70e73661c4975ae46398066c06f8 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Mon, 23 Aug 2010 10:33:19 +1000 Subject: radix-tree: clear all tags in radix_tree_node_rcu_free Commit f446daaea9d4a420d16c606f755f3689dcb2d0ce ("mm: implement writeback livelock avoidance using page tagging") introduced a new radix tree tag, increasing the number of tags in each node from 2 to 3. It did not, however, fix up the code in radix_tree_node_rcu_free() that cleans up after radix_tree_shrink() and hence could leave stray tags set in the new tag array. The result is that the livelock avoidance code added in the the above commit would hit stale tags when doing tag based lookups, resulting in livelocks when trying to traverse the tree. Fix this problem in radix_tree_node_rcu_free() so it doesn't happen again in the future by using a loop to walk all the tags up to RADIX_TREE_MAX_TAGS to clear the stray tags radix_tree_shrink() leaves behind. Signed-off-by: Dave Chinner Acked-by: Nick Piggin Acked-by: Jan Kara diff --git a/lib/radix-tree.c b/lib/radix-tree.c index e907858..1014171 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -174,14 +174,16 @@ static void radix_tree_node_rcu_free(struct rcu_head *head) { struct radix_tree_node *node = container_of(head, struct radix_tree_node, rcu_head); + int i; /* * must only free zeroed nodes into the slab. radix_tree_shrink * can leave us with a non-NULL entry in the first slot, so clear * that here to make sure. */ - tag_clear(node, 0, 0); - tag_clear(node, 1, 0); + for (i = 0; i < RADIX_TREE_MAX_TAGS; i++) + tag_clear(node, i, 0); + node->slots[0] = NULL; node->count = 0; -- cgit v0.10.2 From 144dcfc01221e1a79fa47ca897df7d5e3ab298e6 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Mon, 23 Aug 2010 10:33:53 +1000 Subject: radix-tree: radix_tree_range_tag_if_tagged() can set incorrect tags Commit ebf8aa44beed48cd17893a83d92a4403e5f9d9e2 ("radix-tree: omplement function radix_tree_range_tag_if_tagged") does not safely set tags on on intermediate tree nodes. The code walks down the tree setting tags before it has fully resolved the path to the leaf under the assumption there will be a leaf slot with the tag set in the range it is searching. Unfortunately, this is not a valid assumption - we can abort after setting a tag on an intermediate node if we overrun the number of tags we are allowed to set in a batch, or stop scanning because we we have passed the last scan index before we reach a leaf slot with the tag we are searching for set. As a result, we can leave the function with tags set on intemediate nodes which can be tripped over later by tag-based lookups. The result of these stale tags is that lookup may end prematurely or livelock because the lookup cannot make progress. The fix for the problem involves reocrding the traversal path we take to the leaf nodes, and only propagating the tags back up the tree once the tag is set in the leaf node slot. We are already recording the path for efficient traversal, so there is no additional overhead to do the intermediately node tag setting in this manner. This fixes a radix tree lookup livelock triggered by the new writeback sync livelock avoidance code introduced in commit f446daaea9d4a420d16c606f755f3689dcb2d0ce ("mm: implement writeback livelock avoidance using page tagging"). Signed-off-by: Dave Chinner Acked-by: Jan Kara diff --git a/lib/radix-tree.c b/lib/radix-tree.c index 1014171..e0ee8cb 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -625,6 +625,13 @@ EXPORT_SYMBOL(radix_tree_tag_get); * also settag. The function stops either after tagging nr_to_tag items or * after reaching last_index. * + * The tags must be set from the leaf level only and propagated back up the + * path to the root. We must do this so that we resolve the full path before + * setting any tags on intermediate nodes. If we set tags as we descend, then + * we can get to the leaf node and find that the index that has the iftag + * set is outside the range we are scanning. This reults in dangling tags and + * can lead to problems with later tag operations (e.g. livelocks on lookups). + * * The function returns number of leaves where the tag was set and sets * *first_indexp to the first unscanned index. */ @@ -633,9 +640,13 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root, unsigned long nr_to_tag, unsigned int iftag, unsigned int settag) { - unsigned int height = root->height, shift; - unsigned long tagged = 0, index = *first_indexp; - struct radix_tree_node *open_slots[height], *slot; + unsigned int height = root->height; + struct radix_tree_path path[height]; + struct radix_tree_path *pathp = path; + struct radix_tree_node *slot; + unsigned int shift; + unsigned long tagged = 0; + unsigned long index = *first_indexp; last_index = min(last_index, radix_tree_maxindex(height)); if (index > last_index) @@ -655,6 +666,13 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root, shift = (height - 1) * RADIX_TREE_MAP_SHIFT; slot = radix_tree_indirect_to_ptr(root->rnode); + /* + * we fill the path from (root->height - 2) to 0, leaving the index at + * (root->height - 1) as a terminator. Zero the node in the terminator + * so that we can use this to end walk loops back up the path. + */ + path[height - 1].node = NULL; + for (;;) { int offset; @@ -663,17 +681,30 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root, goto next; if (!tag_get(slot, iftag, offset)) goto next; + if (height > 1) { + /* Go down one level */ + height--; + shift -= RADIX_TREE_MAP_SHIFT; + path[height - 1].node = slot; + path[height - 1].offset = offset; + slot = slot->slots[offset]; + continue; + } + + /* tag the leaf */ + tagged++; tag_set(slot, settag, offset); - if (height == 1) { - tagged++; - goto next; + + /* walk back up the path tagging interior nodes */ + pathp = &path[0]; + while (pathp->node) { + /* stop if we find a node with the tag already set */ + if (tag_get(pathp->node, settag, pathp->offset)) + break; + tag_set(pathp->node, settag, pathp->offset); + pathp++; } - /* Go down one level */ - height--; - shift -= RADIX_TREE_MAP_SHIFT; - open_slots[height] = slot; - slot = slot->slots[offset]; - continue; + next: /* Go to next item at level determined by 'shift' */ index = ((index >> shift) + 1) << shift; @@ -687,7 +718,7 @@ next: * last_index is guaranteed to be in the tree, what * we do below cannot wander astray. */ - slot = open_slots[height]; + slot = path[height - 1].node; height++; shift += RADIX_TREE_MAP_SHIFT; } -- cgit v0.10.2 From 76be97c1fc945db08aae1f1b746012662d643e97 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 22 Aug 2010 17:43:29 -0700 Subject: Linux 2.6.36-rc2 diff --git a/Makefile b/Makefile index f3bdff8..2c0299f 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 36 -EXTRAVERSION = -rc1 +EXTRAVERSION = -rc2 NAME = Sheep on Meth # *DOCUMENTATION* -- cgit v0.10.2 From 09cd2b99c6cdd1e14e84c1febca2fb91e9f4e5ba Mon Sep 17 00:00:00 2001 From: Changli Gao Date: Sun, 22 Aug 2010 17:25:05 +0000 Subject: header: fix broken headers for user space __packed is only defined in kernel space, so we should use __attribute__((packed)) for the code shared between kernel and user space. Two __attribute() annotations are replaced with __attribute__() too. Signed-off-by: Changli Gao Signed-off-by: David S. Miller diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index c831467..bed7a46 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -119,7 +119,7 @@ struct ethhdr { unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ unsigned char h_source[ETH_ALEN]; /* source ether addr */ __be16 h_proto; /* packet type ID field */ -} __packed; +} __attribute__((packed)); #ifdef __KERNEL__ #include diff --git a/include/linux/if_fddi.h b/include/linux/if_fddi.h index 9947c39..e6dc11e 100644 --- a/include/linux/if_fddi.h +++ b/include/linux/if_fddi.h @@ -67,7 +67,7 @@ struct fddi_8022_1_hdr { __u8 dsap; /* destination service access point */ __u8 ssap; /* source service access point */ __u8 ctrl; /* control byte #1 */ -} __packed; +} __attribute__((packed)); /* Define 802.2 Type 2 header */ struct fddi_8022_2_hdr { @@ -75,7 +75,7 @@ struct fddi_8022_2_hdr { __u8 ssap; /* source service access point */ __u8 ctrl_1; /* control byte #1 */ __u8 ctrl_2; /* control byte #2 */ -} __packed; +} __attribute__((packed)); /* Define 802.2 SNAP header */ #define FDDI_K_OUI_LEN 3 @@ -85,7 +85,7 @@ struct fddi_snap_hdr { __u8 ctrl; /* always 0x03 */ __u8 oui[FDDI_K_OUI_LEN]; /* organizational universal id */ __be16 ethertype; /* packet type ID field */ -} __packed; +} __attribute__((packed)); /* Define FDDI LLC frame header */ struct fddihdr { @@ -98,7 +98,7 @@ struct fddihdr { struct fddi_8022_2_hdr llc_8022_2; struct fddi_snap_hdr llc_snap; } hdr; -} __packed; +} __attribute__((packed)); #ifdef __KERNEL__ #include diff --git a/include/linux/if_hippi.h b/include/linux/if_hippi.h index 5fe5f30..cdc049f 100644 --- a/include/linux/if_hippi.h +++ b/include/linux/if_hippi.h @@ -104,7 +104,7 @@ struct hippi_fp_hdr { __be32 fixed; #endif __be32 d2_size; -} __packed; +} __attribute__((packed)); struct hippi_le_hdr { #if defined (__BIG_ENDIAN_BITFIELD) @@ -129,7 +129,7 @@ struct hippi_le_hdr { __u8 daddr[HIPPI_ALEN]; __u16 locally_administered; __u8 saddr[HIPPI_ALEN]; -} __packed; +} __attribute__((packed)); #define HIPPI_OUI_LEN 3 /* @@ -142,12 +142,12 @@ struct hippi_snap_hdr { __u8 ctrl; /* always 0x03 */ __u8 oui[HIPPI_OUI_LEN]; /* organizational universal id (zero)*/ __be16 ethertype; /* packet type ID field */ -} __packed; +} __attribute__((packed)); struct hippi_hdr { struct hippi_fp_hdr fp; struct hippi_le_hdr le; struct hippi_snap_hdr snap; -} __packed; +} __attribute__((packed)); #endif /* _LINUX_IF_HIPPI_H */ diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h index 1925e0c..27741e0 100644 --- a/include/linux/if_pppox.h +++ b/include/linux/if_pppox.h @@ -59,7 +59,7 @@ struct sockaddr_pppox { union{ struct pppoe_addr pppoe; }sa_addr; -} __packed; +} __attribute__((packed)); /* The use of the above union isn't viable because the size of this * struct must stay fixed over time -- applications use sizeof(struct @@ -70,7 +70,7 @@ struct sockaddr_pppol2tp { sa_family_t sa_family; /* address family, AF_PPPOX */ unsigned int sa_protocol; /* protocol identifier */ struct pppol2tp_addr pppol2tp; -} __packed; +} __attribute__((packed)); /* The L2TPv3 protocol changes tunnel and session ids from 16 to 32 * bits. So we need a different sockaddr structure. @@ -79,7 +79,7 @@ struct sockaddr_pppol2tpv3 { sa_family_t sa_family; /* address family, AF_PPPOX */ unsigned int sa_protocol; /* protocol identifier */ struct pppol2tpv3_addr pppol2tp; -} __packed; +} __attribute__((packed)); /********************************************************************* * @@ -101,7 +101,7 @@ struct pppoe_tag { __be16 tag_type; __be16 tag_len; char tag_data[0]; -} __attribute ((packed)); +} __attribute__ ((packed)); /* Tag identifiers */ #define PTT_EOL __cpu_to_be16(0x0000) @@ -129,7 +129,7 @@ struct pppoe_hdr { __be16 sid; __be16 length; struct pppoe_tag tag[0]; -} __packed; +} __attribute__((packed)); /* Length of entire PPPoE + PPP header */ #define PPPOE_SES_HLEN 8 diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index ab9e9e8..e62683b 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -58,7 +58,7 @@ struct ipv6_opt_hdr { /* * TLV encoded option data follows. */ -} __packed; /* required for some archs */ +} __attribute__((packed)); /* required for some archs */ #define ipv6_destopt_hdr ipv6_opt_hdr #define ipv6_hopopt_hdr ipv6_opt_hdr @@ -99,7 +99,7 @@ struct ipv6_destopt_hao { __u8 type; __u8 length; struct in6_addr addr; -} __packed; +} __attribute__((packed)); /* * IPv6 fixed header diff --git a/include/linux/nbd.h b/include/linux/nbd.h index bb58854..d146ca1 100644 --- a/include/linux/nbd.h +++ b/include/linux/nbd.h @@ -88,7 +88,7 @@ struct nbd_request { char handle[8]; __be64 from; __be32 len; -} __packed; +} __attribute__((packed)); /* * This is the reply packet that nbd-server sends back to the client after diff --git a/include/linux/ncp.h b/include/linux/ncp.h index 3ace837..99f0ade 100644 --- a/include/linux/ncp.h +++ b/include/linux/ncp.h @@ -27,7 +27,7 @@ struct ncp_request_header { __u8 conn_high; __u8 function; __u8 data[0]; -} __packed; +} __attribute__((packed)); #define NCP_REPLY (0x3333) #define NCP_WATCHDOG (0x3E3E) @@ -42,7 +42,7 @@ struct ncp_reply_header { __u8 completion_code; __u8 connection_state; __u8 data[0]; -} __packed; +} __attribute__((packed)); #define NCP_VOLNAME_LEN (16) #define NCP_NUMBER_OF_VOLUMES (256) @@ -158,7 +158,7 @@ struct nw_info_struct { #ifdef __KERNEL__ struct nw_nfs_info nfs; #endif -} __packed; +} __attribute__((packed)); /* modify mask - use with MODIFY_DOS_INFO structure */ #define DM_ATTRIBUTES (cpu_to_le32(0x02)) @@ -190,12 +190,12 @@ struct nw_modify_dos_info { __u16 inheritanceGrantMask; __u16 inheritanceRevokeMask; __u32 maximumSpace; -} __packed; +} __attribute__((packed)); struct nw_search_sequence { __u8 volNumber; __u32 dirBase; __u32 sequence; -} __packed; +} __attribute__((packed)); #endif /* _LINUX_NCP_H */ diff --git a/include/linux/netfilter/xt_IDLETIMER.h b/include/linux/netfilter/xt_IDLETIMER.h index 3e1aa1b..208ae93 100644 --- a/include/linux/netfilter/xt_IDLETIMER.h +++ b/include/linux/netfilter/xt_IDLETIMER.h @@ -39,7 +39,7 @@ struct idletimer_tg_info { char label[MAX_IDLETIMER_LABEL_SIZE]; /* for kernel module internal use only */ - struct idletimer_tg *timer __attribute((aligned(8))); + struct idletimer_tg *timer __attribute__((aligned(8))); }; #endif diff --git a/include/linux/phonet.h b/include/linux/phonet.h index 24426c3..76edadf 100644 --- a/include/linux/phonet.h +++ b/include/linux/phonet.h @@ -56,7 +56,7 @@ struct phonethdr { __be16 pn_length; __u8 pn_robj; __u8 pn_sobj; -} __packed; +} __attribute__((packed)); /* Common Phonet payload header */ struct phonetmsg { @@ -98,7 +98,7 @@ struct sockaddr_pn { __u8 spn_dev; __u8 spn_resource; __u8 spn_zero[sizeof(struct sockaddr) - sizeof(sa_family_t) - 3]; -} __packed; +} __attribute__((packed)); /* Well known address */ #define PN_DEV_PC 0x10 diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index 4f82326..08c32e4 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h @@ -81,7 +81,7 @@ struct rfkill_event { __u8 type; __u8 op; __u8 soft, hard; -} __packed; +} __attribute__((packed)); /* * We are planning to be backward and forward compatible with changes -- cgit v0.10.2 From 6a6d01d374d03bd2f90030200cb78567444addc4 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 19 Aug 2010 07:07:23 +0000 Subject: isdn/avm: fix build when PCMCIA is not enabled Why wouldn't kconfig symbol ISDN_DRV_AVMB1_B1PCMCIA also depend on PCMCIA? Fix build for PCMCIA not enabled: ERROR: "b1_free_card" [drivers/isdn/hardware/avm/b1pcmcia.ko] undefined! ERROR: "b1ctl_proc_fops" [drivers/isdn/hardware/avm/b1pcmcia.ko] undefined! ERROR: "b1_reset_ctr" [drivers/isdn/hardware/avm/b1pcmcia.ko] undefined! ERROR: "b1_load_firmware" [drivers/isdn/hardware/avm/b1pcmcia.ko] undefined! ERROR: "b1_send_message" [drivers/isdn/hardware/avm/b1pcmcia.ko] undefined! ERROR: "b1_release_appl" [drivers/isdn/hardware/avm/b1pcmcia.ko] undefined! ERROR: "b1_register_appl" [drivers/isdn/hardware/avm/b1pcmcia.ko] undefined! ERROR: "b1_getrevision" [drivers/isdn/hardware/avm/b1pcmcia.ko] undefined! ERROR: "b1_detect" [drivers/isdn/hardware/avm/b1pcmcia.ko] undefined! ERROR: "b1_interrupt" [drivers/isdn/hardware/avm/b1pcmcia.ko] undefined! ERROR: "b1_alloc_card" [drivers/isdn/hardware/avm/b1pcmcia.ko] undefined! Signed-off-by: Randy Dunlap Cc: Carsten Paeth Cc: Karsten Keil Signed-off-by: David S. Miller diff --git a/drivers/isdn/hardware/avm/Kconfig b/drivers/isdn/hardware/avm/Kconfig index 5dbcbe3..b99b906 100644 --- a/drivers/isdn/hardware/avm/Kconfig +++ b/drivers/isdn/hardware/avm/Kconfig @@ -36,12 +36,13 @@ config ISDN_DRV_AVMB1_T1ISA config ISDN_DRV_AVMB1_B1PCMCIA tristate "AVM B1/M1/M2 PCMCIA support" + depends on PCMCIA help Enable support for the PCMCIA version of the AVM B1 card. config ISDN_DRV_AVMB1_AVM_CS tristate "AVM B1/M1/M2 PCMCIA cs module" - depends on ISDN_DRV_AVMB1_B1PCMCIA && PCMCIA + depends on ISDN_DRV_AVMB1_B1PCMCIA help Enable the PCMCIA client driver for the AVM B1/M1/M2 PCMCIA cards. -- cgit v0.10.2 From 6f0ef6ea1d11ef242de584e345355b0de756fcb2 Mon Sep 17 00:00:00 2001 From: Jerone Young Date: Mon, 23 Aug 2010 08:34:36 +0200 Subject: ALSA: hda - Add support for Lenovo S10-3t This patch adds quirk for the Lenovo S10-3t so the headphone & microphone jacks will now work. Signed-off-by: Jerone Young Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index c424952..5cdb80e 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -3059,6 +3059,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x21b4, "Thinkpad Edge", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G series", CXT5066_IDEAPAD), + SND_PCI_QUIRK(0x17aa, 0x390a, "Lenovo S10-3t", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x3938, "Lenovo G series (AMD)", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD), {} -- cgit v0.10.2 From 97e94c3a57c5999dde878449f17238ae98f74e42 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 13 Aug 2010 17:42:39 -0400 Subject: Blackfin: fix hweight breakage The recent commit to add constant optimization to hweight implicitly broke the Blackfin arch. Seems we were missed when all the other arches were fixed with renames. Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/include/asm/bitops.h b/arch/blackfin/include/asm/bitops.h index d5872cd..3f7ef4d 100644 --- a/arch/blackfin/include/asm/bitops.h +++ b/arch/blackfin/include/asm/bitops.h @@ -22,7 +22,9 @@ #include #include +#include #include + #include #include #include @@ -115,7 +117,7 @@ static inline int test_and_change_bit(int nr, volatile unsigned long *addr) * of bits set) of a N-bit word */ -static inline unsigned int hweight32(unsigned int w) +static inline unsigned int __arch_hweight32(unsigned int w) { unsigned int res; @@ -125,19 +127,20 @@ static inline unsigned int hweight32(unsigned int w) return res; } -static inline unsigned int hweight64(__u64 w) +static inline unsigned int __arch_hweight64(__u64 w) { - return hweight32((unsigned int)(w >> 32)) + hweight32((unsigned int)w); + return __arch_hweight32((unsigned int)(w >> 32)) + + __arch_hweight32((unsigned int)w); } -static inline unsigned int hweight16(unsigned int w) +static inline unsigned int __arch_hweight16(unsigned int w) { - return hweight32(w & 0xffff); + return __arch_hweight32(w & 0xffff); } -static inline unsigned int hweight8(unsigned int w) +static inline unsigned int __arch_hweight8(unsigned int w) { - return hweight32(w & 0xff); + return __arch_hweight32(w & 0xff); } #endif /* _BLACKFIN_BITOPS_H */ -- cgit v0.10.2 From 4bdef3bd7e59a3cabb3dc02ccff9f056d3a06f99 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 11 Aug 2010 23:52:23 -0400 Subject: ADI/ASoC: add MAINTAINERS entries Signed-off-by: Mike Frysinger diff --git a/MAINTAINERS b/MAINTAINERS index 433f353..a1df54b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -454,6 +454,17 @@ L: linux-rdma@vger.kernel.org S: Maintained F: drivers/infiniband/hw/amso1100/ +ANALOG DEVICES INC ASOC DRIVERS +L: uclinux-dist-devel@blackfin.uclinux.org +L: alsa-devel@alsa-project.org (moderated for non-subscribers) +W: http://blackfin.uclinux.org/ +S: Supported +F: sound/soc/blackfin/* +F: sound/soc/codecs/ad1* +F: sound/soc/codecs/adau* +F: sound/soc/codecs/adav* +F: sound/soc/codecs/ssm* + AOA (Apple Onboard Audio) ALSA DRIVER M: Johannes Berg L: linuxppc-dev@lists.ozlabs.org -- cgit v0.10.2 From f3411b16c790e52b5abe174b33c7d213dbf5c259 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 18 Aug 2010 15:25:30 -0400 Subject: Blackfin: wire up new fanotify/prlimit64 syscalls Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/include/asm/unistd.h b/arch/blackfin/include/asm/unistd.h index 22886cb..14fcd25 100644 --- a/arch/blackfin/include/asm/unistd.h +++ b/arch/blackfin/include/asm/unistd.h @@ -389,8 +389,11 @@ #define __NR_rt_tgsigqueueinfo 368 #define __NR_perf_event_open 369 #define __NR_recvmmsg 370 +#define __NR_fanotify_init 371 +#define __NR_fanotify_mark 372 +#define __NR_prlimit64 373 -#define __NR_syscall 371 +#define __NR_syscall 374 #define NR_syscalls __NR_syscall /* Old optional stuff no one actually uses */ diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index a5847f5..af1bffa 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -1628,6 +1628,9 @@ ENTRY(_sys_call_table) .long _sys_rt_tgsigqueueinfo .long _sys_perf_event_open .long _sys_recvmmsg /* 370 */ + .long _sys_fanotify_init + .long _sys_fanotify_mark + .long _sys_prlimit64 .rept NR_syscalls-(.-_sys_call_table)/4 .long _sys_ni_syscall -- cgit v0.10.2 From c6db67cda735d8ace5f19c3831240e1408679790 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 20 Aug 2010 11:49:15 +0200 Subject: watchdog: Don't throttle the watchdog Stephane reported that when the machine locks up, the regular ticks, which are responsible to resetting the throttle count, stop too. Hence the NMI watchdog can end up being throttled before it reports on the locked up state, and we end up being sad.. Cure this by having the watchdog overflow reset its own throttle count. Reported-by: Stephane Eranian Tested-by: Stephane Eranian Cc: Don Zickus Cc: Frederic Weisbecker Signed-off-by: Peter Zijlstra LKML-Reference: <1282215916.1926.4696.camel@laptop> Signed-off-by: Ingo Molnar diff --git a/kernel/watchdog.c b/kernel/watchdog.c index 613bc1f..0d53c8e 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -206,6 +206,9 @@ void watchdog_overflow_callback(struct perf_event *event, int nmi, struct perf_sample_data *data, struct pt_regs *regs) { + /* Ensure the watchdog never gets throttled */ + event->hw.interrupts = 0; + if (__get_cpu_var(watchdog_nmi_touch) == true) { __get_cpu_var(watchdog_nmi_touch) = false; return; -- cgit v0.10.2 From 9d0f4dcc5c4d1c5dd01172172684a45b5f49d740 Mon Sep 17 00:00:00 2001 From: Tim Chen Date: Wed, 18 Aug 2010 15:00:27 -0700 Subject: mutex: Improve the scalability of optimistic spinning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a scalability issue for current implementation of optimistic mutex spin in the kernel. It is found on a 8 node 64 core Nehalem-EX system (HT mode). The intention of the optimistic mutex spin is to busy wait and spin on a mutex if the owner of the mutex is running, in the hope that the mutex will be released soon and be acquired, without the thread trying to acquire mutex going to sleep. However, when we have a large number of threads, contending for the mutex, we could have the mutex grabbed by other thread, and then another ……, and we will keep spinning, wasting cpu cycles and adding to the contention. One possible fix is to quit spinning and put the current thread on wait-list if mutex lock switch to a new owner while we spin, indicating heavy contention (see the patch included). I did some testing on a 8 socket Nehalem-EX system with a total of 64 cores. Using Ingo's test-mutex program that creates/delete files with 256 threads (http://lkml.org/lkml/2006/1/8/50) , I see the following speed up after putting in the mutex spin fix: ./mutex-test V 256 10 Ops/sec 2.6.34 62864 With fix 197200 Repeating the test with Aim7 fserver workload, again there is a speed up with the fix: Jobs/min 2.6.34 91657 With fix 149325 To look at the impact on the distribution of mutex acquisition time, I collected the mutex acquisition time on Aim7 fserver workload with some instrumentation. The average acquisition time is reduced by 48% and number of contentions reduced by 32%. #contentions Time to acquire mutex (cycles) 2.6.34 72973 44765791 With fix 49210 23067129 The histogram of mutex acquisition time is listed below. The acquisition time is in 2^bin cycles. We see that without the fix, the acquisition time is mostly around 2^26 cycles. With the fix, we the distribution get spread out a lot more towards the lower cycles, starting from 2^13. However, there is an increase of the tail distribution with the fix at 2^28 and 2^29 cycles. It seems a small price to pay for the reduced average acquisition time and also getting the cpu to do useful work. Mutex acquisition time distribution (acq time = 2^bin cycles): 2.6.34 With Fix bin #occurrence % #occurrence % 11 2 0.00% 120 0.24% 12 10 0.01% 790 1.61% 13 14 0.02% 2058 4.18% 14 86 0.12% 3378 6.86% 15 393 0.54% 4831 9.82% 16 710 0.97% 4893 9.94% 17 815 1.12% 4667 9.48% 18 790 1.08% 5147 10.46% 19 580 0.80% 6250 12.70% 20 429 0.59% 6870 13.96% 21 311 0.43% 1809 3.68% 22 255 0.35% 2305 4.68% 23 317 0.44% 916 1.86% 24 610 0.84% 233 0.47% 25 3128 4.29% 95 0.19% 26 63902 87.69% 122 0.25% 27 619 0.85% 286 0.58% 28 0 0.00% 3536 7.19% 29 0 0.00% 903 1.83% 30 0 0.00% 0 0.00% I've done similar experiments with 2.6.35 kernel on smaller boxes as well. One is on a dual-socket Westmere box (12 cores total, with HT). Another experiment is on an old dual-socket Core 2 box (4 cores total, no HT) On the 12-core Westmere box, I see a 250% increase for Ingo's mutex-test program with my mutex patch but no significant difference in aim7's fserver workload. On the 4-core Core 2 box, I see the difference with the patch for both mutex-test and aim7 fserver are negligible. So far, it seems like the patch has not caused regression on smaller systems. Signed-off-by: Tim Chen Acked-by: Peter Zijlstra Cc: Linus Torvalds Cc: Andrew Morton Cc: Thomas Gleixner Cc: Frederic Weisbecker Cc: # .35.x LKML-Reference: <1282168827.9542.72.camel@schen9-DESK> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 41541d7..09b574e 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -3865,8 +3865,16 @@ int mutex_spin_on_owner(struct mutex *lock, struct thread_info *owner) /* * Owner changed, break to re-assess state. */ - if (lock->owner != owner) + if (lock->owner != owner) { + /* + * If the lock has switched to a different owner, + * we likely have heavy contention. Return 0 to quit + * optimistic spinning and not contend further: + */ + if (lock->owner) + return 0; break; + } /* * Is that owner really running on that cpu? -- cgit v0.10.2 From f95d76ab82c381ce2221fbe75f331ff1478732db Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 23 Aug 2010 12:39:29 +0200 Subject: ipheth: add support for iPhone 4 This adds support for the iPhone 4 to the ipheth driver. Acked-by: Diego Giagio Signed-off-by: Jens Axboe diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c index 08e7b6a..8ed30fa 100644 --- a/drivers/net/usb/ipheth.c +++ b/drivers/net/usb/ipheth.c @@ -58,6 +58,7 @@ #define USB_PRODUCT_IPHONE 0x1290 #define USB_PRODUCT_IPHONE_3G 0x1292 #define USB_PRODUCT_IPHONE_3GS 0x1294 +#define USB_PRODUCT_IPHONE_4 0x1297 #define IPHETH_USBINTF_CLASS 255 #define IPHETH_USBINTF_SUBCLASS 253 @@ -92,6 +93,10 @@ static struct usb_device_id ipheth_table[] = { USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_3GS, IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, IPHETH_USBINTF_PROTO) }, + { USB_DEVICE_AND_INTERFACE_INFO( + USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4, + IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, + IPHETH_USBINTF_PROTO) }, { } }; MODULE_DEVICE_TABLE(usb, ipheth_table); -- cgit v0.10.2 From c93a4dfb31f2c023da3ad1238c352452f2cc0e05 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Mon, 23 Aug 2010 11:59:28 +0100 Subject: xen: pvhvm: allow user to request no emulated device unplug this allows the user to disable pvhvm and revert to emulated devices in case of a system misconfiguration (e.g. initramfs with only emulated drivers in it). Signed-off-by: Ian Campbell Acked-by: Jeremy Fitzhardinge Acked-by: Stefano Stabellini diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 2c85c06..8bbe83b 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2631,6 +2631,7 @@ and is between 256 and 4096 characters. It is defined in the file all -- unplug all emulated devices (NICs and IDE disks) ignore -- continue loading the Xen platform PCI driver even if the version check failed + never -- do not unplug even if version check succeeds xirc2ps_cs= [NET,PCMCIA] Format: diff --git a/arch/x86/xen/platform-pci-unplug.c b/arch/x86/xen/platform-pci-unplug.c index 554c002..070dfa0 100644 --- a/arch/x86/xen/platform-pci-unplug.c +++ b/arch/x86/xen/platform-pci-unplug.c @@ -72,6 +72,9 @@ void __init xen_unplug_emulated_devices(void) { int r; + /* user explicitly requested no unplug */ + if (xen_emul_unplug & XEN_UNPLUG_NEVER) + return; /* check the version of the xen platform PCI device */ r = check_platform_magic(); /* If the version matches enable the Xen platform PCI driver. @@ -127,6 +130,8 @@ static int __init parse_xen_emul_unplug(char *arg) xen_emul_unplug |= XEN_UNPLUG_ALL_NICS; else if (!strncmp(p, "ignore", l)) xen_emul_unplug |= XEN_UNPLUG_IGNORE; + else if (!strncmp(p, "never", l)) + xen_emul_unplug |= XEN_UNPLUG_NEVER; else printk(KERN_WARNING "unrecognised option '%s' " "in parameter 'xen_emul_unplug'\n", p); diff --git a/include/xen/platform_pci.h b/include/xen/platform_pci.h index ce9d671..123b775 100644 --- a/include/xen/platform_pci.h +++ b/include/xen/platform_pci.h @@ -21,6 +21,7 @@ #define XEN_UNPLUG_AUX_IDE_DISKS 4 #define XEN_UNPLUG_ALL 7 #define XEN_UNPLUG_IGNORE 8 +#define XEN_UNPLUG_NEVER 16 static inline int xen_must_unplug_nics(void) { #if (defined(CONFIG_XEN_NETDEV_FRONTEND) || \ -- cgit v0.10.2 From 1dc7ce99b091a11cce0f34456c1ffcb928f17edd Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Mon, 23 Aug 2010 11:59:29 +0100 Subject: xen: pvhvm: rename xen_emul_unplug=ignore to =unnnecessary It is not immediately clear what this option causes to become ignored. The actual meaning is that it is not necessary to unplug the emulated devices to safely use the PV ones, even if the platform does not support the unplug protocol. (pressumably the user will only add this option if they have ensured that their domain configuration is safe). I think xen_emul_unplug=unnecessary better captures this. Signed-off-by: Ian Campbell Acked-by: Jeremy Fitzhardinge Acked-by: Stefano Stabellini diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 8bbe83b..f084af0 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2629,8 +2629,9 @@ and is between 256 and 4096 characters. It is defined in the file aux-ide-disks -- unplug non-primary-master IDE devices nics -- unplug network devices all -- unplug all emulated devices (NICs and IDE disks) - ignore -- continue loading the Xen platform PCI driver even - if the version check failed + unnecessary -- unplugging emulated devices is + unnecessary even if the host did not respond to + the unplug protocol never -- do not unplug even if version check succeeds xirc2ps_cs= [NET,PCMCIA] diff --git a/arch/x86/xen/platform-pci-unplug.c b/arch/x86/xen/platform-pci-unplug.c index 070dfa0..0f45638 100644 --- a/arch/x86/xen/platform-pci-unplug.c +++ b/arch/x86/xen/platform-pci-unplug.c @@ -78,10 +78,11 @@ void __init xen_unplug_emulated_devices(void) /* check the version of the xen platform PCI device */ r = check_platform_magic(); /* If the version matches enable the Xen platform PCI driver. - * Also enable the Xen platform PCI driver if the version is really old - * and the user told us to ignore it. */ + * Also enable the Xen platform PCI driver if the host does + * not support the unplug protocol (XEN_PLATFORM_ERR_MAGIC) + * but the user told us that unplugging is unnecessary. */ if (r && !(r == XEN_PLATFORM_ERR_MAGIC && - (xen_emul_unplug & XEN_UNPLUG_IGNORE))) + (xen_emul_unplug & XEN_UNPLUG_UNNECESSARY))) return; /* Set the default value of xen_emul_unplug depending on whether or * not the Xen PV frontends and the Xen platform PCI driver have @@ -102,7 +103,7 @@ void __init xen_unplug_emulated_devices(void) } } /* Now unplug the emulated devices */ - if (!(xen_emul_unplug & XEN_UNPLUG_IGNORE)) + if (!(xen_emul_unplug & XEN_UNPLUG_UNNECESSARY)) outw(xen_emul_unplug, XEN_IOPORT_UNPLUG); xen_platform_pci_unplug = xen_emul_unplug; } @@ -128,8 +129,8 @@ static int __init parse_xen_emul_unplug(char *arg) xen_emul_unplug |= XEN_UNPLUG_AUX_IDE_DISKS; else if (!strncmp(p, "nics", l)) xen_emul_unplug |= XEN_UNPLUG_ALL_NICS; - else if (!strncmp(p, "ignore", l)) - xen_emul_unplug |= XEN_UNPLUG_IGNORE; + else if (!strncmp(p, "unnecessary", l)) + xen_emul_unplug |= XEN_UNPLUG_UNNECESSARY; else if (!strncmp(p, "never", l)) xen_emul_unplug |= XEN_UNPLUG_NEVER; else diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index ac1b682e..ab735a6 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -834,7 +834,7 @@ static int blkfront_probe(struct xenbus_device *dev, char *type; int len; /* no unplug has been done: do not hook devices != xen vbds */ - if (xen_platform_pci_unplug & XEN_UNPLUG_IGNORE) { + if (xen_platform_pci_unplug & XEN_UNPLUG_UNNECESSARY) { int major; if (!VDEV_IS_EXTENDED(vdevice)) diff --git a/include/xen/platform_pci.h b/include/xen/platform_pci.h index 123b775..590ccfd 100644 --- a/include/xen/platform_pci.h +++ b/include/xen/platform_pci.h @@ -20,7 +20,7 @@ #define XEN_UNPLUG_ALL_NICS 2 #define XEN_UNPLUG_AUX_IDE_DISKS 4 #define XEN_UNPLUG_ALL 7 -#define XEN_UNPLUG_IGNORE 8 +#define XEN_UNPLUG_UNNECESSARY 8 #define XEN_UNPLUG_NEVER 16 static inline int xen_must_unplug_nics(void) { -- cgit v0.10.2 From 9c35e90c6fcf7f5baf27a63d9565e9f47633f299 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Mon, 23 Aug 2010 12:01:35 +0100 Subject: xen: pvhvm: make it clearer that XEN_UNPLUG_* define bits in a bitfield by defining in terms of (1< Acked-by: Jeremy Fitzhardinge Acked-by: Stefano Stabellini diff --git a/include/xen/platform_pci.h b/include/xen/platform_pci.h index 590ccfd..a785a3b 100644 --- a/include/xen/platform_pci.h +++ b/include/xen/platform_pci.h @@ -16,12 +16,15 @@ #define XEN_IOPORT_PROTOVER (XEN_IOPORT_BASE + 2) /* 1 byte access (R) */ #define XEN_IOPORT_PRODNUM (XEN_IOPORT_BASE + 2) /* 2 byte access (W) */ -#define XEN_UNPLUG_ALL_IDE_DISKS 1 -#define XEN_UNPLUG_ALL_NICS 2 -#define XEN_UNPLUG_AUX_IDE_DISKS 4 -#define XEN_UNPLUG_ALL 7 -#define XEN_UNPLUG_UNNECESSARY 8 -#define XEN_UNPLUG_NEVER 16 +#define XEN_UNPLUG_ALL_IDE_DISKS (1<<0) +#define XEN_UNPLUG_ALL_NICS (1<<1) +#define XEN_UNPLUG_AUX_IDE_DISKS (1<<2) +#define XEN_UNPLUG_ALL (XEN_UNPLUG_ALL_IDE_DISKS|\ + XEN_UNPLUG_ALL_NICS|\ + XEN_UNPLUG_AUX_IDE_DISKS) + +#define XEN_UNPLUG_UNNECESSARY (1<<16) +#define XEN_UNPLUG_NEVER (1<<17) static inline int xen_must_unplug_nics(void) { #if (defined(CONFIG_XEN_NETDEV_FRONTEND) || \ -- cgit v0.10.2 From 31fc0bd4aab30cac3e3388883b1b62750cc2f648 Mon Sep 17 00:00:00 2001 From: Rupjyoti Sarmah Date: Fri, 4 Jun 2010 00:03:12 +0000 Subject: powerpc/4xx: Device tree update for the 460ex DWC SATA Device tree update for the Applied micro processor 460ex on-chip SATA Signed-off-by: Rupjyoti Sarmah Signed-off-by: Josh Boyer diff --git a/arch/powerpc/boot/dts/canyonlands.dts b/arch/powerpc/boot/dts/canyonlands.dts index 5806ef0..a303703 100644 --- a/arch/powerpc/boot/dts/canyonlands.dts +++ b/arch/powerpc/boot/dts/canyonlands.dts @@ -163,6 +163,14 @@ interrupts = <0x1e 4>; }; + SATA0: sata@bffd1000 { + compatible = "amcc,sata-460ex"; + reg = <4 0xbffd1000 0x800 4 0xbffd0800 0x400>; + interrupt-parent = <&UIC3>; + interrupts = <0x0 0x4 /* SATA */ + 0x5 0x4>; /* AHBDMA */ + }; + POB0: opb { compatible = "ibm,opb-460ex", "ibm,opb"; #address-cells = <1>; -- cgit v0.10.2 From 029b8f662b24a35aab20a81087822f1badf5463c Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Wed, 18 Aug 2010 06:44:23 +0000 Subject: powerpc/47x: Make sure mcsr is cleared before enabling machine check interrupts Clear the machine check syndrom register before enabling machine check interrupts. The initial state of the tlb can lead to parity errors being flagged early after a cold boot. Signed-off-by: Dave Kleikamp Signed-off-by: Josh Boyer diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S index 5ab484e..562305b 100644 --- a/arch/powerpc/kernel/head_44x.S +++ b/arch/powerpc/kernel/head_44x.S @@ -113,6 +113,10 @@ _ENTRY(_start); stw r5, 0(r4) /* Save abatron_pteptrs at a fixed location */ stw r6, 0(r5) + /* Clear the Machine Check Syndrome Register */ + li r0,0 + mtspr SPRN_MCSR,r0 + /* Let's move on */ lis r4,start_kernel@h ori r4,r4,start_kernel@l -- cgit v0.10.2 From 66477466b8b79c98af17f1c2267596c8b6b4b561 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Wed, 18 Aug 2010 06:44:24 +0000 Subject: powerpc/47x: Remove redundant line from cputable.c There are two entries for .cpu_user_features in arch/powerpc/kernel/cputable.c. Remove the one that doesn't belong Signed-off-by: Dave Kleikamp Signed-off-by: Josh Boyer diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 65e2b4e..1f9123f 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -1826,7 +1826,6 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_47X, .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU, - .cpu_user_features = COMMON_USER_BOOKE, .mmu_features = MMU_FTR_TYPE_47x | MMU_FTR_USE_TLBIVAX_BCAST | MMU_FTR_LOCK_BCAST_INVAL, .icache_bsize = 32, -- cgit v0.10.2 From 3e7f45ad521ac3e38889d255ec7676037fa84ae2 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Wed, 18 Aug 2010 06:44:25 +0000 Subject: powerpc/4xx: Index interrupt stacks by physical cpu The interrupt stacks need to be indexed by the physical cpu since the critical, debug and machine check handlers use the contents of SPRN_PIR to index the critirq_ctx, dbgirq_ctx, and mcheckirq_ctx arrays. Signed-off-by: Dave Kleikamp Signed-off-by: Josh Boyer diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index d3ce67c..4a65386 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -67,6 +67,7 @@ #include #include #include +#include #ifdef CONFIG_PPC64 #include @@ -446,22 +447,23 @@ struct thread_info *mcheckirq_ctx[NR_CPUS] __read_mostly; void exc_lvl_ctx_init(void) { struct thread_info *tp; - int i; + int i, hw_cpu; for_each_possible_cpu(i) { - memset((void *)critirq_ctx[i], 0, THREAD_SIZE); - tp = critirq_ctx[i]; + hw_cpu = get_hard_smp_processor_id(i); + memset((void *)critirq_ctx[hw_cpu], 0, THREAD_SIZE); + tp = critirq_ctx[hw_cpu]; tp->cpu = i; tp->preempt_count = 0; #ifdef CONFIG_BOOKE - memset((void *)dbgirq_ctx[i], 0, THREAD_SIZE); - tp = dbgirq_ctx[i]; + memset((void *)dbgirq_ctx[hw_cpu], 0, THREAD_SIZE); + tp = dbgirq_ctx[hw_cpu]; tp->cpu = i; tp->preempt_count = 0; - memset((void *)mcheckirq_ctx[i], 0, THREAD_SIZE); - tp = mcheckirq_ctx[i]; + memset((void *)mcheckirq_ctx[hw_cpu], 0, THREAD_SIZE); + tp = mcheckirq_ctx[hw_cpu]; tp->cpu = i; tp->preempt_count = HARDIRQ_OFFSET; #endif diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index a10ffc8..93666f9 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -258,17 +258,18 @@ static void __init irqstack_early_init(void) #if defined(CONFIG_BOOKE) || defined(CONFIG_40x) static void __init exc_lvl_early_init(void) { - unsigned int i; + unsigned int i, hw_cpu; /* interrupt stacks must be in lowmem, we get that for free on ppc32 * as the memblock is limited to lowmem by MEMBLOCK_REAL_LIMIT */ for_each_possible_cpu(i) { - critirq_ctx[i] = (struct thread_info *) + hw_cpu = get_hard_smp_processor_id(i); + critirq_ctx[hw_cpu] = (struct thread_info *) __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE)); #ifdef CONFIG_BOOKE - dbgirq_ctx[i] = (struct thread_info *) + dbgirq_ctx[hw_cpu] = (struct thread_info *) __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE)); - mcheckirq_ctx[i] = (struct thread_info *) + mcheckirq_ctx[hw_cpu] = (struct thread_info *) __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE)); #endif } -- cgit v0.10.2 From 32412aa214e05308833a89e6090406294833f989 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Wed, 18 Aug 2010 06:44:26 +0000 Subject: powerpc/47x: Add an isync before the tlbivax instruction Signed-off-by: Dave Kleikamp Signed-off-by: Josh Boyer diff --git a/arch/powerpc/mm/tlb_nohash_low.S b/arch/powerpc/mm/tlb_nohash_low.S index cfa7682..b9d9fed 100644 --- a/arch/powerpc/mm/tlb_nohash_low.S +++ b/arch/powerpc/mm/tlb_nohash_low.S @@ -200,6 +200,7 @@ _GLOBAL(_tlbivax_bcast) rlwimi r5,r4,0,16,31 wrteei 0 mtspr SPRN_MMUCR,r5 + isync /* tlbivax 0,r3 - use .long to avoid binutils deps */ .long 0x7c000624 | (r3 << 11) isync -- cgit v0.10.2 From 70bf043b137aa9ff2711b16532774465e07a8f47 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 23 Aug 2010 08:54:02 +0200 Subject: ASoC: i.MX ssi: use SSI_STCCR in synchronous mode In synchronous mode the SSI_SRCCR values are ignored. Instead SSI_STCCR must be used for both receiving and transmitting. Signed-off-by: Sascha Hauer Acked-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c index a11daa1..c81da05 100644 --- a/sound/soc/imx/imx-ssi.c +++ b/sound/soc/imx/imx-ssi.c @@ -254,6 +254,9 @@ static int imx_ssi_hw_params(struct snd_pcm_substream *substream, dma_data = &ssi->dma_params_rx; } + if (ssi->flags & IMX_SSI_SYN) + reg = SSI_STCCR; + snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data); sccr = readl(ssi->base + reg) & ~SSI_STCCR_WL_MASK; -- cgit v0.10.2 From 6e0c64f4ddf4a76a04108c1e24132d5d7dea8872 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 23 Aug 2010 14:31:34 +0100 Subject: arch/mn10300/mm: eliminate NULL dereference dev_name always dereferences its argument, so it should not be called if the argument is NULL. The function indeed later tests the argument for being NULL. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression dev,E; @@ *dev_name(dev) ... when != dev = E ( *dev == NULL | *dev != NULL ) // Signed-off-by: Julia Lawall Signed-off-by: David Howells Signed-off-by: Linus Torvalds diff --git a/arch/mn10300/mm/dma-alloc.c b/arch/mn10300/mm/dma-alloc.c index 4e34880..159acb0 100644 --- a/arch/mn10300/mm/dma-alloc.c +++ b/arch/mn10300/mm/dma-alloc.c @@ -25,7 +25,8 @@ void *dma_alloc_coherent(struct device *dev, size_t size, unsigned long addr; void *ret; - printk("dma_alloc_coherent(%s,%zu,,%x)\n", dev_name(dev), size, gfp); + pr_debug("dma_alloc_coherent(%s,%zu,%x)\n", + dev ? dev_name(dev) : "?", size, gfp); if (0xbe000000 - pci_sram_allocated >= size) { size = (size + 255) & ~255; -- cgit v0.10.2 From c76a3e1d6c52c5cc1371f1abc7381c5715ebdf7f Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Mon, 23 Aug 2010 11:32:36 -0600 Subject: ACPI_TOSHIBA needs LEDS support Don't ask how ACPI_TOSHIBA got enabled on in desktop system's .config - I don't know. But it has silently been there until I tried 2.6.36-rc2, where it broke the build because I don't have LED support turned on. Attached patch fixes things up. (I had to change BACKLIGHT_CLASS_DEVICE to "depends" because otherwise I get unsightly core dumps out of scripts/kconfig/conf). jon -- toshiba: make sure we pull in LED support The Toshiba extras driver uses the LED module, so make sure we have it configure in. Signed-off-by: Jonathan Corbet Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 044f430..cff7cc2 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -486,10 +486,12 @@ config TOPSTAR_LAPTOP config ACPI_TOSHIBA tristate "Toshiba Laptop Extras" depends on ACPI + depends on LEDS_CLASS + depends on NEW_LEDS + depends on BACKLIGHT_CLASS_DEVICE depends on INPUT depends on RFKILL || RFKILL = n select INPUT_POLLDEV - select BACKLIGHT_CLASS_DEVICE ---help--- This driver adds support for access to certain system settings on "legacy free" Toshiba laptops. These laptops can be recognized by -- cgit v0.10.2 From a8ec105c0764c848d59f18a31f91fa00c99b2e7f Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Mon, 23 Aug 2010 15:52:34 -0400 Subject: hp-wmi: Fix query interface The machines I have appear to provide their return value in the arguments structure, not the output structure. Rework the driver to use that again in order to get rfkill working again. Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index f155163..c174114 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -79,12 +79,13 @@ struct bios_args { u32 command; u32 commandtype; u32 datasize; - char *data; + u32 data; }; struct bios_return { u32 sigpass; u32 return_code; + u32 value; }; struct key_entry { @@ -148,7 +149,7 @@ static struct platform_driver hp_wmi_driver = { * buffer = kzalloc(128, GFP_KERNEL); * ret = hp_wmi_perform_query(0x7, 0, buffer, 128) */ -static int hp_wmi_perform_query(int query, int write, char *buffer, +static int hp_wmi_perform_query(int query, int write, u32 *buffer, int buffersize) { struct bios_return bios_return; @@ -159,7 +160,7 @@ static int hp_wmi_perform_query(int query, int write, char *buffer, .command = write ? 0x2 : 0x1, .commandtype = query, .datasize = buffersize, - .data = buffer, + .data = *buffer, }; struct acpi_buffer input = { sizeof(struct bios_args), &args }; struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -177,29 +178,14 @@ static int hp_wmi_perform_query(int query, int write, char *buffer, bios_return = *((struct bios_return *)obj->buffer.pointer); - if (bios_return.return_code) { - printk(KERN_WARNING PREFIX "Query %d returned %d\n", query, - bios_return.return_code); - kfree(obj); - return bios_return.return_code; - } - if (obj->buffer.length - sizeof(bios_return) > buffersize) { - kfree(obj); - return -EINVAL; - } - - memset(buffer, 0, buffersize); - memcpy(buffer, - ((char *)obj->buffer.pointer) + sizeof(struct bios_return), - obj->buffer.length - sizeof(bios_return)); - kfree(obj); + memcpy(buffer, &bios_return.value, sizeof(bios_return.value)); return 0; } static int hp_wmi_display_state(void) { - int state; - int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, (char *)&state, + int state = 0; + int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, &state, sizeof(state)); if (ret) return -EINVAL; @@ -208,8 +194,8 @@ static int hp_wmi_display_state(void) static int hp_wmi_hddtemp_state(void) { - int state; - int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, (char *)&state, + int state = 0; + int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, &state, sizeof(state)); if (ret) return -EINVAL; @@ -218,8 +204,8 @@ static int hp_wmi_hddtemp_state(void) static int hp_wmi_als_state(void) { - int state; - int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, (char *)&state, + int state = 0; + int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, &state, sizeof(state)); if (ret) return -EINVAL; @@ -228,8 +214,8 @@ static int hp_wmi_als_state(void) static int hp_wmi_dock_state(void) { - int state; - int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, (char *)&state, + int state = 0; + int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, sizeof(state)); if (ret) @@ -240,8 +226,8 @@ static int hp_wmi_dock_state(void) static int hp_wmi_tablet_state(void) { - int state; - int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, (char *)&state, + int state = 0; + int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, sizeof(state)); if (ret) return ret; @@ -256,7 +242,7 @@ static int hp_wmi_set_block(void *data, bool blocked) int ret; ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, - (char *)&query, sizeof(query)); + &query, sizeof(query)); if (ret) return -EINVAL; return 0; @@ -268,10 +254,10 @@ static const struct rfkill_ops hp_wmi_rfkill_ops = { static bool hp_wmi_get_sw_state(enum hp_wmi_radio r) { - int wireless; + int wireless = 0; int mask; hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, - (char *)&wireless, sizeof(wireless)); + &wireless, sizeof(wireless)); /* TBD: Pass error */ mask = 0x200 << (r * 8); @@ -284,10 +270,10 @@ static bool hp_wmi_get_sw_state(enum hp_wmi_radio r) static bool hp_wmi_get_hw_state(enum hp_wmi_radio r) { - int wireless; + int wireless = 0; int mask; hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, - (char *)&wireless, sizeof(wireless)); + &wireless, sizeof(wireless)); /* TBD: Pass error */ mask = 0x800 << (r * 8); @@ -347,7 +333,7 @@ static ssize_t set_als(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { u32 tmp = simple_strtoul(buf, NULL, 10); - int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, (char *)&tmp, + int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, &tmp, sizeof(tmp)); if (ret) return -EINVAL; @@ -421,7 +407,7 @@ static void hp_wmi_notify(u32 value, void *context) static struct key_entry *key; union acpi_object *obj; u32 event_id, event_data; - int key_code, ret; + int key_code = 0, ret; u32 *location; acpi_status status; @@ -475,7 +461,7 @@ static void hp_wmi_notify(u32 value, void *context) break; case HPWMI_BEZEL_BUTTON: ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0, - (char *)&key_code, + &key_code, sizeof(key_code)); if (ret) break; @@ -578,9 +564,9 @@ static void cleanup_sysfs(struct platform_device *device) static int __devinit hp_wmi_bios_setup(struct platform_device *device) { int err; - int wireless; + int wireless = 0; - err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, (char *)&wireless, + err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless, sizeof(wireless)); if (err) return err; -- cgit v0.10.2 From cca77b7c81876d819a5806f408b3c29b5b61a815 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 23 Aug 2010 14:41:22 -0700 Subject: netfilter: fix CONFIG_COMPAT support commit f3c5c1bfd430858d3a05436f82c51e53104feb6b (netfilter: xtables: make ip_tables reentrant) forgot to also compute the jumpstack size in the compat handlers. Result is that "iptables -I INPUT -j userchain" turns into -j DROP. Reported by Sebastian Roesner on #netfilter, closes http://bugzilla.netfilter.org/show_bug.cgi?id=669. Note: arptables change is compile-tested only. Signed-off-by: Florian Westphal Acked-by: Eric Dumazet Tested-by: Mikael Pettersson Signed-off-by: David S. Miller diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 51d6c31..e8f4f9a 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -1420,6 +1420,9 @@ static int translate_compat_table(const char *name, if (ret != 0) break; ++i; + if (strcmp(arpt_get_target(iter1)->u.user.name, + XT_ERROR_TARGET) == 0) + ++newinfo->stacksize; } if (ret) { /* diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 97b64b2..d163f2e 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -1751,6 +1751,9 @@ translate_compat_table(struct net *net, if (ret != 0) break; ++i; + if (strcmp(ipt_get_target(iter1)->u.user.name, + XT_ERROR_TARGET) == 0) + ++newinfo->stacksize; } if (ret) { /* diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 29a7bca..8e754be 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -1766,6 +1766,9 @@ translate_compat_table(struct net *net, if (ret != 0) break; ++i; + if (strcmp(ip6t_get_target(iter1)->u.user.name, + XT_ERROR_TARGET) == 0) + ++newinfo->stacksize; } if (ret) { /* -- cgit v0.10.2 From 8488a38f4d2f43bd55a3e0db4cd57a5bef3af6d6 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 11 Aug 2010 15:01:02 +0100 Subject: kobject: Break the kobject namespace defs into their own header Break the kobject namespace defs into their own header to avoid a header file inclusion ordering problem between linux/sysfs.h and linux/kobject.h. This fixes the build breakage on older versions of gcc. Signed-off-by: David Howells Cc: Eric Biederman Signed-off-by: Greg Kroah-Hartman diff --git a/include/linux/kobject.h b/include/linux/kobject.h index cf343a8..7950a37 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -136,42 +137,8 @@ struct kobj_attribute { extern const struct sysfs_ops kobj_sysfs_ops; -/* - * Namespace types which are used to tag kobjects and sysfs entries. - * Network namespace will likely be the first. - */ -enum kobj_ns_type { - KOBJ_NS_TYPE_NONE = 0, - KOBJ_NS_TYPE_NET, - KOBJ_NS_TYPES -}; - struct sock; -/* - * Callbacks so sysfs can determine namespaces - * @current_ns: return calling task's namespace - * @netlink_ns: return namespace to which a sock belongs (right?) - * @initial_ns: return the initial namespace (i.e. init_net_ns) - */ -struct kobj_ns_type_operations { - enum kobj_ns_type type; - const void *(*current_ns)(void); - const void *(*netlink_ns)(struct sock *sk); - const void *(*initial_ns)(void); -}; - -int kobj_ns_type_register(const struct kobj_ns_type_operations *ops); -int kobj_ns_type_registered(enum kobj_ns_type type); -const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent); -const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj); - -const void *kobj_ns_current(enum kobj_ns_type type); -const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk); -const void *kobj_ns_initial(enum kobj_ns_type type); -void kobj_ns_exit(enum kobj_ns_type type, const void *ns); - - /** * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem. * diff --git a/include/linux/kobject_ns.h b/include/linux/kobject_ns.h new file mode 100644 index 0000000..82cb5bf --- /dev/null +++ b/include/linux/kobject_ns.h @@ -0,0 +1,56 @@ +/* Kernel object name space definitions + * + * Copyright (c) 2002-2003 Patrick Mochel + * Copyright (c) 2002-2003 Open Source Development Labs + * Copyright (c) 2006-2008 Greg Kroah-Hartman + * Copyright (c) 2006-2008 Novell Inc. + * + * Split from kobject.h by David Howells (dhowells@redhat.com) + * + * This file is released under the GPLv2. + * + * Please read Documentation/kobject.txt before using the kobject + * interface, ESPECIALLY the parts about reference counts and object + * destructors. + */ + +#ifndef _LINUX_KOBJECT_NS_H +#define _LINUX_KOBJECT_NS_H + +struct sock; +struct kobject; + +/* + * Namespace types which are used to tag kobjects and sysfs entries. + * Network namespace will likely be the first. + */ +enum kobj_ns_type { + KOBJ_NS_TYPE_NONE = 0, + KOBJ_NS_TYPE_NET, + KOBJ_NS_TYPES +}; + +/* + * Callbacks so sysfs can determine namespaces + * @current_ns: return calling task's namespace + * @netlink_ns: return namespace to which a sock belongs (right?) + * @initial_ns: return the initial namespace (i.e. init_net_ns) + */ +struct kobj_ns_type_operations { + enum kobj_ns_type type; + const void *(*current_ns)(void); + const void *(*netlink_ns)(struct sock *sk); + const void *(*initial_ns)(void); +}; + +int kobj_ns_type_register(const struct kobj_ns_type_operations *ops); +int kobj_ns_type_registered(enum kobj_ns_type type); +const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent); +const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj); + +const void *kobj_ns_current(enum kobj_ns_type type); +const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk); +const void *kobj_ns_initial(enum kobj_ns_type type); +void kobj_ns_exit(enum kobj_ns_type type, const void *ns); + +#endif /* _LINUX_KOBJECT_NS_H */ diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 3c92121..96eb576 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -16,6 +16,7 @@ #include #include #include +#include #include struct kobject; -- cgit v0.10.2 From f45f3c1f3f616ca1d1e1eb5e7a720ca63cb59550 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 18 Aug 2010 17:15:18 +0200 Subject: firmware_class: fix typo in error path In the error path, _request_firmware sets firmware_p to NULL rather than *firmware_p, which leads to passing a freed firmware struct to drivers when the firmware file cannot be found. Fix this. Broken by commit f8a4bd3456b988fc73b2c. Reported-by: Wey-Yi Guy Signed-off-by: Johannes Berg Acked-by: Dmitry Torokhov Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index c8a44f5..40af43e 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -568,7 +568,7 @@ static int _request_firmware(const struct firmware **firmware_p, out: if (retval) { release_firmware(firmware); - firmware_p = NULL; + *firmware_p = NULL; } return retval; -- cgit v0.10.2 From f6e6e7799ebcad40fa15e4015beca2d776554302 Mon Sep 17 00:00:00 2001 From: Xiaotian Feng Date: Fri, 13 Aug 2010 18:58:10 +0800 Subject: kobject_uevent: fix typo in comments s/ending/sending, s/kobject_uevent()/kobject_uevent_env() in the comments. Signed-off-by: Xiaotian Feng Signed-off-by: Greg Kroah-Hartman diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index b935795..70af0a7 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -123,7 +123,7 @@ static int kobj_usermode_filter(struct kobject *kobj) * @kobj: struct kobject that the action is happening to * @envp_ext: pointer to environmental data * - * Returns 0 if kobject_uevent() is completed with success or the + * Returns 0 if kobject_uevent_env() is completed with success or the * corresponding error when it fails. */ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, @@ -317,7 +317,7 @@ exit: EXPORT_SYMBOL_GPL(kobject_uevent_env); /** - * kobject_uevent - notify userspace by ending an uevent + * kobject_uevent - notify userspace by sending an uevent * * @action: action that is happening * @kobj: struct kobject that the action is happening to -- cgit v0.10.2 From 09e74c794fc9d5064e07c4bf6c9d5458586385c1 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 9 Jul 2010 23:25:12 -0400 Subject: Staging: spectra: removes q->prepare_flush_fn, fix build breakage This patch is the first one of a patchset that allows stagin/spectra driver to compile in linux-next. blk_queue_ordered doesn't receive a prepare flush function anymore Signed-off-by: Javier Martinez Canillas Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/spectra/ffsport.c b/drivers/staging/spectra/ffsport.c index d0c5c97..eca6536 100644 --- a/drivers/staging/spectra/ffsport.c +++ b/drivers/staging/spectra/ffsport.c @@ -272,13 +272,6 @@ static int get_res_blk_num_os(void) return res_blks; } -static void SBD_prepare_flush(struct request_queue *q, struct request *rq) -{ - rq->cmd_type = REQ_TYPE_LINUX_BLOCK; - /* rq->timeout = 5 * HZ; */ - rq->cmd[0] = REQ_LB_OP_FLUSH; -} - /* Transfer a full request. */ static int do_transfer(struct spectra_nand_dev *tr, struct request *req) { @@ -650,8 +643,7 @@ static int SBD_setup_device(struct spectra_nand_dev *dev, int which) /* Here we force report 512 byte hardware sector size to Kernel */ blk_queue_logical_block_size(dev->queue, 512); - blk_queue_ordered(dev->queue, QUEUE_ORDERED_DRAIN_FLUSH, - SBD_prepare_flush); + blk_queue_ordered(dev->queue, QUEUE_ORDERED_DRAIN_FLUSH); dev->thread = kthread_run(spectra_trans_thread, dev, "nand_thd"); if (IS_ERR(dev->thread)) { -- cgit v0.10.2 From 7b633f6624ce4ea6199a54c2cad6c9e84164f8f5 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 9 Jul 2010 23:28:13 -0400 Subject: Staging: use new REQ_FLUSH flag, fix build breakage REQ_TYPE_LINUX_BLOCK and REQ_LB_OP_FLUSH doesn't exist anymore. Using the new REQ_FLUSH flag instead Signed-off-by: Javier Martinez Canillas Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/spectra/ffsport.c b/drivers/staging/spectra/ffsport.c index eca6536..00a0ac0 100644 --- a/drivers/staging/spectra/ffsport.c +++ b/drivers/staging/spectra/ffsport.c @@ -289,8 +289,7 @@ static int do_transfer(struct spectra_nand_dev *tr, struct request *req) IdentifyDeviceData.PagesPerBlock * res_blks_os; - if (req->cmd_type == REQ_TYPE_LINUX_BLOCK && - req->cmd[0] == REQ_LB_OP_FLUSH) { + if (req->cmd_type & REQ_FLUSH) { if (force_flush_cache()) /* Fail to flush cache */ return -EIO; else -- cgit v0.10.2 From 6e19d2db499b66aa7942bd36a7b55bb725379aae Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Sat, 10 Jul 2010 00:07:35 -0400 Subject: Staging: spectra: don't use locked_ioctl, fix build Last patch has a style problem. Sending the correct one. Sorry for the noise Since BKL was removed from block ioctl handling code, locked_ioctl doesn't exist anymore. Using ioctl instead and doing the locking manually. Signed-off-by: Javier Martinez Canillas Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/spectra/ffsport.c b/drivers/staging/spectra/ffsport.c index 00a0ac0..7b34635 100644 --- a/drivers/staging/spectra/ffsport.c +++ b/drivers/staging/spectra/ffsport.c @@ -27,6 +27,7 @@ #include #include #include +#include /**** Helper functions used for Div, Remainder operation on u64 ****/ @@ -589,11 +590,23 @@ int GLOB_SBD_ioctl(struct block_device *bdev, fmode_t mode, return -ENOTTY; } +int GLOB_SBD_unlocked_ioctl(struct block_device *bdev, fmode_t mode, + unsigned int cmd, unsigned long arg) +{ + int ret; + + lock_kernel(); + ret = GLOB_SBD_ioctl(bdev, mode, cmd, arg); + unlock_kernel(); + + return ret; +} + static struct block_device_operations GLOB_SBD_ops = { .owner = THIS_MODULE, .open = GLOB_SBD_open, .release = GLOB_SBD_release, - .locked_ioctl = GLOB_SBD_ioctl, + .ioctl = GLOB_SBD_unlocked_ioctl, .getgeo = GLOB_SBD_getgeo, }; -- cgit v0.10.2 From c321da6dc53cd692dc2db82686d5dfd150a3b817 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Sat, 17 Jul 2010 16:39:54 -0400 Subject: Staging: spectra: remove duplicate GLOB_VERSION definition This is the first patch of a patchset that removes all compilations warnings in staging/spectra. These patches are a delta from a previous patchset and it assumes that these three patches all already applied: Signed-off-by: Javier Martinez Canillas Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/spectra/ffsport.c b/drivers/staging/spectra/ffsport.c index 7b34635..44a7fbe 100644 --- a/drivers/staging/spectra/ffsport.c +++ b/drivers/staging/spectra/ffsport.c @@ -114,7 +114,6 @@ u64 GLOB_u64_Remainder(u64 addr, u32 divisor_type) #define GLOB_SBD_NAME "nd" #define GLOB_SBD_IRQ_NUM (29) -#define GLOB_VERSION "driver version 20091110" #define GLOB_SBD_IOCTL_GC (0x7701) #define GLOB_SBD_IOCTL_WL (0x7702) -- cgit v0.10.2 From 676cecaaddd09bbe41a38b1d15f190da10087294 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Sat, 17 Jul 2010 16:42:19 -0400 Subject: Staging: spectra: removes unused variable Fix a compile warning by removing an unused variable int i. Signed-off-by: Javier Martinez Canillas Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/spectra/flash.c b/drivers/staging/spectra/flash.c index 134aa51..a0d6094 100644 --- a/drivers/staging/spectra/flash.c +++ b/drivers/staging/spectra/flash.c @@ -775,7 +775,7 @@ static void dump_cache_l2_table(void) { struct list_head *p; struct spectra_l2_cache_list *pnd; - int n, i; + int n; n = 0; list_for_each(p, &cache_l2.table.list) { -- cgit v0.10.2 From fd484b86a22efeea06298c0dc3b1518473ff2fc4 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Sat, 17 Jul 2010 16:45:27 -0400 Subject: Staging: spectra: initializa lblk variable Fix a compile warning by initializaing lblk. Since FTL_Get_Block_Index() returns BAD_BLOCK if it doesn't find the logical block number, lblk number is initizalized to BAD_BLOCK. Signed-off-by: Javier Martinez Canillas Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/spectra/flash.c b/drivers/staging/spectra/flash.c index a0d6094..2673388 100644 --- a/drivers/staging/spectra/flash.c +++ b/drivers/staging/spectra/flash.c @@ -1698,7 +1698,7 @@ static int get_l2_cache_blks(void) static int erase_l2_cache_blocks(void) { int i, ret = PASS; - u32 pblk, lblk; + u32 pblk, lblk = BAD_BLOCK; u64 addr; u32 *pbt = (u32 *)g_pBlockTable; -- cgit v0.10.2 From 49b48547724eca062aec13a3bfd621194836513b Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Sat, 17 Jul 2010 16:46:28 -0400 Subject: Staging: spectra: removes unused functions Fix compilation warning removing unused functions. Signed-off-by: Javier Martinez Canillas Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/spectra/flash.c b/drivers/staging/spectra/flash.c index 2673388..9b5218b 100644 --- a/drivers/staging/spectra/flash.c +++ b/drivers/staging/spectra/flash.c @@ -61,7 +61,6 @@ static void FTL_Cache_Read_Page(u8 *pData, u64 dwPageAddr, static void FTL_Cache_Write_Page(u8 *pData, u64 dwPageAddr, u8 cache_blk, u16 flag); static int FTL_Cache_Write(void); -static int FTL_Cache_Write_Back(u8 *pData, u64 blk_addr); static void FTL_Calculate_LRU(void); static u32 FTL_Get_Block_Index(u32 wBlockNum); @@ -86,8 +85,6 @@ static u32 FTL_Replace_MWBlock(void); static int FTL_Replace_Block(u64 blk_addr); static int FTL_Adjust_Relative_Erase_Count(u32 Index_of_MAX); -static int FTL_Flash_Error_Handle(u8 *pData, u64 old_page_addr, u64 blk_addr); - struct device_info_tag DeviceInfo; struct flash_cache_tag Cache; static struct spectra_l2_cache_info cache_l2; @@ -1538,79 +1535,6 @@ static int FTL_Cache_Write_All(u8 *pData, u64 blk_addr) } /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Cache_Update_Block -* Inputs: pointer to buffer,page address,block address -* Outputs: PASS=0 / FAIL=1 -* Description: It updates the cache -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static int FTL_Cache_Update_Block(u8 *pData, - u64 old_page_addr, u64 blk_addr) -{ - int i, j; - u8 *buf = pData; - int wResult = PASS; - int wFoundInCache; - u64 page_addr; - u64 addr; - u64 old_blk_addr; - u16 page_offset; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - old_blk_addr = (u64)(old_page_addr >> - DeviceInfo.nBitsInBlockDataSize) * DeviceInfo.wBlockDataSize; - page_offset = (u16)(GLOB_u64_Remainder(old_page_addr, 2) >> - DeviceInfo.nBitsInPageDataSize); - - for (i = 0; i < DeviceInfo.wPagesPerBlock; i += Cache.pages_per_item) { - page_addr = old_blk_addr + i * DeviceInfo.wPageDataSize; - if (i != page_offset) { - wFoundInCache = FAIL; - for (j = 0; j < CACHE_ITEM_NUM; j++) { - addr = Cache.array[j].address; - addr = FTL_Get_Physical_Block_Addr(addr) + - GLOB_u64_Remainder(addr, 2); - if ((addr >= page_addr) && addr < - (page_addr + Cache.cache_item_size)) { - wFoundInCache = PASS; - buf = Cache.array[j].buf; - Cache.array[j].changed = SET; -#if CMD_DMA -#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE - int_cache[ftl_cmd_cnt].item = j; - int_cache[ftl_cmd_cnt].cache.address = - Cache.array[j].address; - int_cache[ftl_cmd_cnt].cache.changed = - Cache.array[j].changed; -#endif -#endif - break; - } - } - if (FAIL == wFoundInCache) { - if (ERR == FTL_Cache_Read_All(g_pTempBuf, - page_addr)) { - wResult = FAIL; - break; - } - buf = g_pTempBuf; - } - } else { - buf = pData; - } - - if (FAIL == FTL_Cache_Write_All(buf, - blk_addr + (page_addr - old_blk_addr))) { - wResult = FAIL; - break; - } - } - - return wResult; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& * Function: FTL_Copy_Block * Inputs: source block address * Destination block address @@ -2004,87 +1928,6 @@ static int search_l2_cache(u8 *buf, u64 logical_addr) return ret; } -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Cache_Write_Back -* Inputs: pointer to data cached in sys memory -* address of free block in flash -* Outputs: PASS=0 / FAIL=1 -* Description: writes all the pages of Cache Block to flash -* -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static int FTL_Cache_Write_Back(u8 *pData, u64 blk_addr) -{ - int i, j, iErase; - u64 old_page_addr, addr, phy_addr; - u32 *pbt = (u32 *)g_pBlockTable; - u32 lba; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - old_page_addr = FTL_Get_Physical_Block_Addr(blk_addr) + - GLOB_u64_Remainder(blk_addr, 2); - - iErase = (FAIL == FTL_Replace_Block(blk_addr)) ? PASS : FAIL; - - pbt[BLK_FROM_ADDR(blk_addr)] &= (~SPARE_BLOCK); - -#if CMD_DMA - p_BTableChangesDelta = (struct BTableChangesDelta *)g_pBTDelta_Free; - g_pBTDelta_Free += sizeof(struct BTableChangesDelta); - - p_BTableChangesDelta->ftl_cmd_cnt = ftl_cmd_cnt; - p_BTableChangesDelta->BT_Index = (u32)(blk_addr >> - DeviceInfo.nBitsInBlockDataSize); - p_BTableChangesDelta->BT_Entry_Value = - pbt[(u32)(blk_addr >> DeviceInfo.nBitsInBlockDataSize)]; - p_BTableChangesDelta->ValidFields = 0x0C; -#endif - - if (IN_PROGRESS_BLOCK_TABLE != g_cBlockTableStatus) { - g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE; - FTL_Write_IN_Progress_Block_Table_Page(); - } - - for (i = 0; i < RETRY_TIMES; i++) { - if (PASS == iErase) { - phy_addr = FTL_Get_Physical_Block_Addr(blk_addr); - if (FAIL == GLOB_FTL_Block_Erase(phy_addr)) { - lba = BLK_FROM_ADDR(blk_addr); - MARK_BLOCK_AS_BAD(pbt[lba]); - i = RETRY_TIMES; - break; - } - } - - for (j = 0; j < CACHE_ITEM_NUM; j++) { - addr = Cache.array[j].address; - if ((addr <= blk_addr) && - ((addr + Cache.cache_item_size) > blk_addr)) - cache_block_to_write = j; - } - - phy_addr = FTL_Get_Physical_Block_Addr(blk_addr); - if (PASS == FTL_Cache_Update_Block(pData, - old_page_addr, phy_addr)) { - cache_block_to_write = UNHIT_CACHE_ITEM; - break; - } else { - iErase = PASS; - } - } - - if (i >= RETRY_TIMES) { - if (ERR == FTL_Flash_Error_Handle(pData, - old_page_addr, blk_addr)) - return ERR; - else - return FAIL; - } - - return PASS; -} - /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& * Function: FTL_Cache_Write_Page * Inputs: Pointer to buffer, page address, cache block number @@ -2370,159 +2213,6 @@ static int FTL_Write_Block_Table(int wForce) return 1; } -/****************************************************************** -* Function: GLOB_FTL_Flash_Format -* Inputs: none -* Outputs: PASS -* Description: The block table stores bad block info, including MDF+ -* blocks gone bad over the ages. Therefore, if we have a -* block table in place, then use it to scan for bad blocks -* If not, then scan for MDF. -* Now, a block table will only be found if spectra was already -* being used. For a fresh flash, we'll go thru scanning for -* MDF. If spectra was being used, then there is a chance that -* the MDF has been corrupted. Spectra avoids writing to the -* first 2 bytes of the spare area to all pages in a block. This -* covers all known flash devices. However, since flash -* manufacturers have no standard of where the MDF is stored, -* this cannot guarantee that the MDF is protected for future -* devices too. The initial scanning for the block table assures -* this. It is ok even if the block table is outdated, as all -* we're looking for are bad block markers. -* Use this when mounting a file system or starting a -* new flash. -* -*********************************************************************/ -static int FTL_Format_Flash(u8 valid_block_table) -{ - u32 i, j; - u32 *pbt = (u32 *)g_pBlockTable; - u32 tempNode; - int ret; - -#if CMD_DMA - u32 *pbtStartingCopy = (u32 *)g_pBTStartingCopy; - if (ftl_cmd_cnt) - return FAIL; -#endif - - if (FAIL == FTL_Check_Block_Table(FAIL)) - valid_block_table = 0; - - if (valid_block_table) { - u8 switched = 1; - u32 block, k; - - k = DeviceInfo.wSpectraStartBlock; - while (switched && (k < DeviceInfo.wSpectraEndBlock)) { - switched = 0; - k++; - for (j = DeviceInfo.wSpectraStartBlock, i = 0; - j <= DeviceInfo.wSpectraEndBlock; - j++, i++) { - block = (pbt[i] & ~BAD_BLOCK) - - DeviceInfo.wSpectraStartBlock; - if (block != i) { - switched = 1; - tempNode = pbt[i]; - pbt[i] = pbt[block]; - pbt[block] = tempNode; - } - } - } - if ((k == DeviceInfo.wSpectraEndBlock) && switched) - valid_block_table = 0; - } - - if (!valid_block_table) { - memset(g_pBlockTable, 0, - DeviceInfo.wDataBlockNum * sizeof(u32)); - memset(g_pWearCounter, 0, - DeviceInfo.wDataBlockNum * sizeof(u8)); - if (DeviceInfo.MLCDevice) - memset(g_pReadCounter, 0, - DeviceInfo.wDataBlockNum * sizeof(u16)); -#if CMD_DMA - memset(g_pBTStartingCopy, 0, - DeviceInfo.wDataBlockNum * sizeof(u32)); - memset(g_pWearCounterCopy, 0, - DeviceInfo.wDataBlockNum * sizeof(u8)); - if (DeviceInfo.MLCDevice) - memset(g_pReadCounterCopy, 0, - DeviceInfo.wDataBlockNum * sizeof(u16)); -#endif - for (j = DeviceInfo.wSpectraStartBlock, i = 0; - j <= DeviceInfo.wSpectraEndBlock; - j++, i++) { - if (GLOB_LLD_Get_Bad_Block((u32)j)) - pbt[i] = (u32)(BAD_BLOCK | j); - } - } - - nand_dbg_print(NAND_DBG_WARN, "Erasing all blocks in the NAND\n"); - - for (j = DeviceInfo.wSpectraStartBlock, i = 0; - j <= DeviceInfo.wSpectraEndBlock; - j++, i++) { - if ((pbt[i] & BAD_BLOCK) != BAD_BLOCK) { - ret = GLOB_LLD_Erase_Block(j); - if (FAIL == ret) { - pbt[i] = (u32)(j); - MARK_BLOCK_AS_BAD(pbt[i]); - nand_dbg_print(NAND_DBG_WARN, - "NAND Program fail in %s, Line %d, " - "Function: %s, new Bad Block %d generated!\n", - __FILE__, __LINE__, __func__, (int)j); - } else { - pbt[i] = (u32)(SPARE_BLOCK | j); - } - } -#if CMD_DMA - pbtStartingCopy[i] = pbt[i]; -#endif - } - - g_wBlockTableOffset = 0; - for (i = 0; (i <= (DeviceInfo.wSpectraEndBlock - - DeviceInfo.wSpectraStartBlock)) - && ((pbt[i] & BAD_BLOCK) == BAD_BLOCK); i++) - ; - if (i > (DeviceInfo.wSpectraEndBlock - DeviceInfo.wSpectraStartBlock)) { - printk(KERN_ERR "All blocks bad!\n"); - return FAIL; - } else { - g_wBlockTableIndex = pbt[i] & ~BAD_BLOCK; - if (i != BLOCK_TABLE_INDEX) { - tempNode = pbt[i]; - pbt[i] = pbt[BLOCK_TABLE_INDEX]; - pbt[BLOCK_TABLE_INDEX] = tempNode; - } - } - pbt[BLOCK_TABLE_INDEX] &= (~SPARE_BLOCK); - -#if CMD_DMA - pbtStartingCopy[BLOCK_TABLE_INDEX] &= (~SPARE_BLOCK); -#endif - - g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE; - memset(g_pBTBlocks, 0xFF, - (1 + LAST_BT_ID - FIRST_BT_ID) * sizeof(u32)); - g_pBTBlocks[FIRST_BT_ID-FIRST_BT_ID] = g_wBlockTableIndex; - FTL_Write_Block_Table(FAIL); - - for (i = 0; i < CACHE_ITEM_NUM; i++) { - Cache.array[i].address = NAND_CACHE_INIT_ADDR; - Cache.array[i].use_cnt = 0; - Cache.array[i].changed = CLEAR; - } - -#if (RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE && CMD_DMA) - memcpy((void *)&cache_start_copy, (void *)&Cache, - sizeof(struct flash_cache_tag)); -#endif - return PASS; -} - static int force_format_nand(void) { u32 i; @@ -3031,112 +2721,6 @@ static int FTL_Read_Block_Table(void) return wResult; } - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Flash_Error_Handle -* Inputs: Pointer to data -* Page address -* Block address -* Outputs: PASS=0 / FAIL=1 -* Description: It handles any error occured during Spectra operation -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static int FTL_Flash_Error_Handle(u8 *pData, u64 old_page_addr, - u64 blk_addr) -{ - u32 i; - int j; - u32 tmp_node, blk_node = BLK_FROM_ADDR(blk_addr); - u64 phy_addr; - int wErase = FAIL; - int wResult = FAIL; - u32 *pbt = (u32 *)g_pBlockTable; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (ERR == GLOB_FTL_Garbage_Collection()) - return ERR; - - do { - for (i = DeviceInfo.wSpectraEndBlock - - DeviceInfo.wSpectraStartBlock; - i > 0; i--) { - if (IS_SPARE_BLOCK(i)) { - tmp_node = (u32)(BAD_BLOCK | - pbt[blk_node]); - pbt[blk_node] = (u32)(pbt[i] & - (~SPARE_BLOCK)); - pbt[i] = tmp_node; -#if CMD_DMA - p_BTableChangesDelta = - (struct BTableChangesDelta *) - g_pBTDelta_Free; - g_pBTDelta_Free += - sizeof(struct BTableChangesDelta); - - p_BTableChangesDelta->ftl_cmd_cnt = - ftl_cmd_cnt; - p_BTableChangesDelta->BT_Index = - blk_node; - p_BTableChangesDelta->BT_Entry_Value = - pbt[blk_node]; - p_BTableChangesDelta->ValidFields = 0x0C; - - p_BTableChangesDelta = - (struct BTableChangesDelta *) - g_pBTDelta_Free; - g_pBTDelta_Free += - sizeof(struct BTableChangesDelta); - - p_BTableChangesDelta->ftl_cmd_cnt = - ftl_cmd_cnt; - p_BTableChangesDelta->BT_Index = i; - p_BTableChangesDelta->BT_Entry_Value = pbt[i]; - p_BTableChangesDelta->ValidFields = 0x0C; -#endif - wResult = PASS; - break; - } - } - - if (FAIL == wResult) { - if (FAIL == GLOB_FTL_Garbage_Collection()) - break; - else - continue; - } - - if (IN_PROGRESS_BLOCK_TABLE != g_cBlockTableStatus) { - g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE; - FTL_Write_IN_Progress_Block_Table_Page(); - } - - phy_addr = FTL_Get_Physical_Block_Addr(blk_addr); - - for (j = 0; j < RETRY_TIMES; j++) { - if (PASS == wErase) { - if (FAIL == GLOB_FTL_Block_Erase(phy_addr)) { - MARK_BLOCK_AS_BAD(pbt[blk_node]); - break; - } - } - if (PASS == FTL_Cache_Update_Block(pData, - old_page_addr, - phy_addr)) { - wResult = PASS; - break; - } else { - wResult = FAIL; - wErase = PASS; - } - } - } while (FAIL == wResult); - - FTL_Write_Block_Table(FAIL); - - return wResult; -} - /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& * Function: FTL_Get_Page_Num * Inputs: Size in bytes -- cgit v0.10.2 From 466122df80e447883588ffcf9d21b88152934819 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Mon, 9 Aug 2010 23:56:38 +0200 Subject: Staging: batman-adv: Fix merge of linus tree Greg Kroah-Hartman merged Linus 2.6.36 tree in e9563355ac1175dd3440dc2ea5c28b27ed51a283 with his staging tree. Different parts of the merge conflicts were resolved incorrectly and may result in an abnormal behavior. Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/batman-adv/bat_sysfs.c b/drivers/staging/batman-adv/bat_sysfs.c index b4a8d5e..05ca15a 100644 --- a/drivers/staging/batman-adv/bat_sysfs.c +++ b/drivers/staging/batman-adv/bat_sysfs.c @@ -267,6 +267,10 @@ static ssize_t store_log_level(struct kobject *kobj, struct attribute *attr, if (atomic_read(&bat_priv->log_level) == log_level_tmp) return count; + bat_info(net_dev, "Changing log level from: %i to: %li\n", + atomic_read(&bat_priv->log_level), + log_level_tmp); + atomic_set(&bat_priv->log_level, (unsigned)log_level_tmp); return count; } diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c index 92c216a..f6345c4 100644 --- a/drivers/staging/batman-adv/hard-interface.c +++ b/drivers/staging/batman-adv/hard-interface.c @@ -442,8 +442,6 @@ int batman_skb_recv(struct sk_buff *skb, struct net_device *dev, struct bat_priv *bat_priv = netdev_priv(soft_device); struct batman_packet *batman_packet; struct batman_if *batman_if; - struct net_device_stats *stats; - struct rtnl_link_stats64 temp; int ret; skb = skb_share_check(skb, GFP_ATOMIC); @@ -479,12 +477,6 @@ int batman_skb_recv(struct sk_buff *skb, struct net_device *dev, if (batman_if->if_status != IF_ACTIVE) goto err_free; - stats = (struct net_device_stats *)dev_get_stats(skb->dev, &temp); - if (stats) { - stats->rx_packets++; - stats->rx_bytes += skb->len; - } - batman_packet = (struct batman_packet *)skb->data; if (batman_packet->version != COMPAT_VERSION) { -- cgit v0.10.2 From 9abc10238e1df7ce81c58a441f65efd5e905b9e8 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Mon, 9 Aug 2010 23:56:39 +0200 Subject: Staging: batman-adv: unify orig_hash_lock spinlock handling to avoid deadlocks The orig_hash_lock spinlock always has to be locked with IRQs being disabled to avoid deadlocks between code that is being executed in IRQ context and code that is being executed in non-IRQ context. Reported-by: Sven Eckelmann Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/batman-adv/originator.c b/drivers/staging/batman-adv/originator.c index 28bb627..de5a8c1 100644 --- a/drivers/staging/batman-adv/originator.c +++ b/drivers/staging/batman-adv/originator.c @@ -391,11 +391,12 @@ static int orig_node_add_if(struct orig_node *orig_node, int max_if_num) int orig_hash_add_if(struct batman_if *batman_if, int max_if_num) { struct orig_node *orig_node; + unsigned long flags; HASHIT(hashit); /* resize all orig nodes because orig_node->bcast_own(_sum) depend on * if_num */ - spin_lock(&orig_hash_lock); + spin_lock_irqsave(&orig_hash_lock, flags); while (hash_iterate(orig_hash, &hashit)) { orig_node = hashit.bucket->data; @@ -404,11 +405,11 @@ int orig_hash_add_if(struct batman_if *batman_if, int max_if_num) goto err; } - spin_unlock(&orig_hash_lock); + spin_unlock_irqrestore(&orig_hash_lock, flags); return 0; err: - spin_unlock(&orig_hash_lock); + spin_unlock_irqrestore(&orig_hash_lock, flags); return -ENOMEM; } @@ -468,12 +469,13 @@ int orig_hash_del_if(struct batman_if *batman_if, int max_if_num) { struct batman_if *batman_if_tmp; struct orig_node *orig_node; + unsigned long flags; HASHIT(hashit); int ret; /* resize all orig nodes because orig_node->bcast_own(_sum) depend on * if_num */ - spin_lock(&orig_hash_lock); + spin_lock_irqsave(&orig_hash_lock, flags); while (hash_iterate(orig_hash, &hashit)) { orig_node = hashit.bucket->data; @@ -500,10 +502,10 @@ int orig_hash_del_if(struct batman_if *batman_if, int max_if_num) rcu_read_unlock(); batman_if->if_num = -1; - spin_unlock(&orig_hash_lock); + spin_unlock_irqrestore(&orig_hash_lock, flags); return 0; err: - spin_unlock(&orig_hash_lock); + spin_unlock_irqrestore(&orig_hash_lock, flags); return -ENOMEM; } -- cgit v0.10.2 From 13334d4875dbaeeb44e7905463f07e236f80311f Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Mon, 9 Aug 2010 23:56:40 +0200 Subject: Staging: batman-adv: fix batman icmp originating from secondary interface If a batman icmp packet had to be routed over a secondary interface at the first hop, the mac address of that secondary interface would be written in the 'orig' field of the icmp packet. A node which is more than one hop away is not aware of the mac address because secondary interfaces are not flooded through the whole mesh and therefore can't send a reply. This patch always sends the mac address of the primary interface in the 'orig' field of the icmp packet. Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/batman-adv/icmp_socket.c b/drivers/staging/batman-adv/icmp_socket.c index fc3d32c..3ae7dd2 100644 --- a/drivers/staging/batman-adv/icmp_socket.c +++ b/drivers/staging/batman-adv/icmp_socket.c @@ -67,6 +67,7 @@ static int bat_socket_open(struct inode *inode, struct file *file) INIT_LIST_HEAD(&socket_client->queue_list); socket_client->queue_len = 0; socket_client->index = i; + socket_client->bat_priv = inode->i_private; spin_lock_init(&socket_client->lock); init_waitqueue_head(&socket_client->queue_wait); @@ -151,9 +152,8 @@ static ssize_t bat_socket_read(struct file *file, char __user *buf, static ssize_t bat_socket_write(struct file *file, const char __user *buff, size_t len, loff_t *off) { - /* FIXME: each orig_node->batman_if will be attached to a softif */ - struct bat_priv *bat_priv = netdev_priv(soft_device); struct socket_client *socket_client = file->private_data; + struct bat_priv *bat_priv = socket_client->bat_priv; struct icmp_packet_rr icmp_packet; struct orig_node *orig_node; struct batman_if *batman_if; @@ -168,6 +168,9 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, return -EINVAL; } + if (!bat_priv->primary_if) + return -EFAULT; + if (len >= sizeof(struct icmp_packet_rr)) packet_len = sizeof(struct icmp_packet_rr); @@ -223,7 +226,8 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, if (batman_if->if_status != IF_ACTIVE) goto dst_unreach; - memcpy(icmp_packet.orig, batman_if->net_dev->dev_addr, ETH_ALEN); + memcpy(icmp_packet.orig, + bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); if (packet_len == sizeof(struct icmp_packet_rr)) memcpy(icmp_packet.rr, batman_if->net_dev->dev_addr, ETH_ALEN); @@ -271,7 +275,7 @@ int bat_socket_setup(struct bat_priv *bat_priv) goto err; d = debugfs_create_file(ICMP_SOCKET, S_IFREG | S_IWUSR | S_IRUSR, - bat_priv->debug_dir, NULL, &fops); + bat_priv->debug_dir, bat_priv, &fops); if (d) goto err; diff --git a/drivers/staging/batman-adv/types.h b/drivers/staging/batman-adv/types.h index 21d0717..9aa9d36 100644 --- a/drivers/staging/batman-adv/types.h +++ b/drivers/staging/batman-adv/types.h @@ -126,6 +126,7 @@ struct socket_client { unsigned char index; spinlock_t lock; wait_queue_head_t queue_wait; + struct bat_priv *bat_priv; }; struct socket_packet { -- cgit v0.10.2 From b7a23bce7bc9cac85eab1b958e922b2c472ab8fd Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Mon, 9 Aug 2010 23:56:41 +0200 Subject: Staging: batman-adv: always reply batman icmp packets with primary mac When receiving an batman icmp echo request or in case of a time-to-live exceeded batman would reply with the mac address of the outgoing interface which might be a secondary interface. Because secondary interfaces are not globally known this might lead to confusion. Now, replies are sent with the mac address of the primary interface. Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c index 066cc91..032195e 100644 --- a/drivers/staging/batman-adv/routing.c +++ b/drivers/staging/batman-adv/routing.c @@ -783,6 +783,8 @@ int recv_bat_packet(struct sk_buff *skb, static int recv_my_icmp_packet(struct sk_buff *skb, size_t icmp_len) { + /* FIXME: each batman_if will be attached to a softif */ + struct bat_priv *bat_priv = netdev_priv(soft_device); struct orig_node *orig_node; struct icmp_packet_rr *icmp_packet; struct ethhdr *ethhdr; @@ -801,6 +803,9 @@ static int recv_my_icmp_packet(struct sk_buff *skb, size_t icmp_len) return NET_RX_DROP; } + if (!bat_priv->primary_if) + return NET_RX_DROP; + /* answer echo request (ping) */ /* get routing information */ spin_lock_irqsave(&orig_hash_lock, flags); @@ -830,7 +835,8 @@ static int recv_my_icmp_packet(struct sk_buff *skb, size_t icmp_len) } memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); - memcpy(icmp_packet->orig, ethhdr->h_dest, ETH_ALEN); + memcpy(icmp_packet->orig, + bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); icmp_packet->msg_type = ECHO_REPLY; icmp_packet->ttl = TTL; @@ -845,6 +851,8 @@ static int recv_my_icmp_packet(struct sk_buff *skb, size_t icmp_len) static int recv_icmp_ttl_exceeded(struct sk_buff *skb, size_t icmp_len) { + /* FIXME: each batman_if will be attached to a softif */ + struct bat_priv *bat_priv = netdev_priv(soft_device); struct orig_node *orig_node; struct icmp_packet *icmp_packet; struct ethhdr *ethhdr; @@ -865,6 +873,9 @@ static int recv_icmp_ttl_exceeded(struct sk_buff *skb, size_t icmp_len) return NET_RX_DROP; } + if (!bat_priv->primary_if) + return NET_RX_DROP; + /* get routing information */ spin_lock_irqsave(&orig_hash_lock, flags); orig_node = ((struct orig_node *) @@ -892,7 +903,8 @@ static int recv_icmp_ttl_exceeded(struct sk_buff *skb, size_t icmp_len) } memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); - memcpy(icmp_packet->orig, ethhdr->h_dest, ETH_ALEN); + memcpy(icmp_packet->orig, + bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); icmp_packet->msg_type = TTL_EXCEEDED; icmp_packet->ttl = TTL; -- cgit v0.10.2 From 51e21ae3d79e608022271f91166c84bd0e9fb8b8 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Mon, 9 Aug 2010 23:56:42 +0200 Subject: Staging: batman-adv: fix own mac address detection Earlier batman-adv versions would only create a batman_if struct after a corresponding interface had been activated by a user. Now each existing system interface has a batman_if struct and has to be checked by verifying the IF_ACTIVE flag. Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/batman-adv/main.c b/drivers/staging/batman-adv/main.c index 2686019..ef7c20a 100644 --- a/drivers/staging/batman-adv/main.c +++ b/drivers/staging/batman-adv/main.c @@ -250,10 +250,13 @@ int choose_orig(void *data, int32_t size) int is_my_mac(uint8_t *addr) { struct batman_if *batman_if; + rcu_read_lock(); list_for_each_entry_rcu(batman_if, &if_list, list) { - if ((batman_if->net_dev) && - (compare_orig(batman_if->net_dev->dev_addr, addr))) { + if (batman_if->if_status != IF_ACTIVE) + continue; + + if (compare_orig(batman_if->net_dev->dev_addr, addr)) { rcu_read_unlock(); return 1; } -- cgit v0.10.2 From 1189f130f89b73eecb6117c0fc5e90abbcb7faa0 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sat, 21 Aug 2010 14:18:08 +0200 Subject: Staging: batman-adv: Create batman_if only on register event We try to get all events for all net_devices to be able to add special sysfs folders for the batman-adv configuration. This also includes such events like NETDEV_POST_INIT which has no valid kobject according to v2.6.32-rc3-13-g7ffbe3f. This would create an oops in that situation. It is enough to create the batman_if only on NETDEV_REGISTER events because we will also receive those events for devices which already existed when we registered the notifier call. Signed-off-by: Sven Eckelmann Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c index f6345c4..892166b 100644 --- a/drivers/staging/batman-adv/hard-interface.c +++ b/drivers/staging/batman-adv/hard-interface.c @@ -393,15 +393,13 @@ static int hard_if_event(struct notifier_block *this, /* FIXME: each batman_if will be attached to a softif */ struct bat_priv *bat_priv = netdev_priv(soft_device); - if (!batman_if) - batman_if = hardif_add_interface(net_dev); + if (!batman_if && event == NETDEV_REGISTER) + batman_if = hardif_add_interface(net_dev); if (!batman_if) goto out; switch (event) { - case NETDEV_REGISTER: - break; case NETDEV_UP: hardif_activate_interface(soft_device, bat_priv, batman_if); break; -- cgit v0.10.2 From 51a00eaf6e008b60943af6ab68c17ac3622208dc Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sat, 21 Aug 2010 14:18:09 +0200 Subject: Staging: batman-adv: Don't use net_dev after dev_put dev_put allows a device to be freed when all its references are dropped. After that we are not allowed to access that information anymore. Access to the data structure of a net_device must be surrounded a dev_hold and ended using dev_put. batman-adv adds a device to its own management structure in hardif_add_interface and will release it in hardif_remove_interface. Thus it must hold a reference all the time between those functions to prevent any access to the already released net_device structure. Reported-by: Tim Glaremin Signed-off-by: Sven Eckelmann Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c index 892166b..d08491e 100644 --- a/drivers/staging/batman-adv/hard-interface.c +++ b/drivers/staging/batman-adv/hard-interface.c @@ -194,8 +194,6 @@ static void hardif_activate_interface(struct net_device *net_dev, if (batman_if->if_status != IF_INACTIVE) return; - dev_hold(batman_if->net_dev); - update_mac_addresses(batman_if); batman_if->if_status = IF_TO_BE_ACTIVATED; @@ -222,8 +220,6 @@ static void hardif_deactivate_interface(struct net_device *net_dev, (batman_if->if_status != IF_TO_BE_ACTIVATED)) return; - dev_put(batman_if->net_dev); - batman_if->if_status = IF_INACTIVE; bat_info(net_dev, "Interface deactivated: %s\n", batman_if->dev); @@ -318,11 +314,13 @@ static struct batman_if *hardif_add_interface(struct net_device *net_dev) if (ret != 1) goto out; + dev_hold(net_dev); + batman_if = kmalloc(sizeof(struct batman_if), GFP_ATOMIC); if (!batman_if) { pr_err("Can't add interface (%s): out of memory\n", net_dev->name); - goto out; + goto release_dev; } batman_if->dev = kstrdup(net_dev->name, GFP_ATOMIC); @@ -346,6 +344,8 @@ free_dev: kfree(batman_if->dev); free_if: kfree(batman_if); +release_dev: + dev_put(net_dev); out: return NULL; } @@ -374,6 +374,7 @@ static void hardif_remove_interface(struct batman_if *batman_if) batman_if->if_status = IF_TO_BE_REMOVED; list_del_rcu(&batman_if->list); sysfs_del_hardif(&batman_if->hardif_obj); + dev_put(batman_if->net_dev); call_rcu(&batman_if->rcu, hardif_free_interface); } -- cgit v0.10.2 From f86b9984250fa2b71ce36d4693a939a58579583b Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sat, 21 Aug 2010 14:18:10 +0200 Subject: Staging: batman-adv: Don't write in not allocated packet_buff Each net_device in a system will automatically managed as a possible batman_if and holds different informations like a buffer with a prepared originator messages. To reduce the memory usage, the packet_buff will only be allocated when the interface is really added/enabled for batman-adv. The function to update the hw address information inside the packet_buff just assumes that the packet_buff is always initialised and thus the kernel will just oops when we try to change the hw address of a not already fully enabled interface. We must always check if the packet_buff is allocated before we try to change information inside of it. Reported-by: Tim Glaremin Reported-by: Kazuki Shimada Signed-off-by: Sven Eckelmann Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c index d08491e..baa8b05 100644 --- a/drivers/staging/batman-adv/hard-interface.c +++ b/drivers/staging/batman-adv/hard-interface.c @@ -129,6 +129,9 @@ static bool hardif_is_iface_up(struct batman_if *batman_if) static void update_mac_addresses(struct batman_if *batman_if) { + if (!batman_if || !batman_if->packet_buff) + return; + addr_to_string(batman_if->addr_str, batman_if->net_dev->dev_addr); memcpy(((struct batman_packet *)(batman_if->packet_buff))->orig, @@ -334,6 +337,7 @@ static struct batman_if *hardif_add_interface(struct net_device *net_dev) batman_if->if_num = -1; batman_if->net_dev = net_dev; batman_if->if_status = IF_NOT_IN_USE; + batman_if->packet_buff = NULL; INIT_LIST_HEAD(&batman_if->list); check_known_mac_addr(batman_if->net_dev->dev_addr); -- cgit v0.10.2 From d49824c06778830c82906884b94d94354c3bbdc8 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 23 Aug 2010 10:28:31 -0700 Subject: Staging: sep: remove driver It's currently stalled and the original submitter recommended that it just be dropped at this point in time due. Cc: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 4a7a7a7..335311a 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -113,8 +113,6 @@ source "drivers/staging/vme/Kconfig" source "drivers/staging/memrar/Kconfig" -source "drivers/staging/sep/Kconfig" - source "drivers/staging/iio/Kconfig" source "drivers/staging/zram/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index ca5c03e..e3f1e1b 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -38,7 +38,6 @@ obj-$(CONFIG_FB_UDL) += udlfb/ obj-$(CONFIG_HYPERV) += hv/ obj-$(CONFIG_VME_BUS) += vme/ obj-$(CONFIG_MRST_RAR_HANDLER) += memrar/ -obj-$(CONFIG_DX_SEP) += sep/ obj-$(CONFIG_IIO) += iio/ obj-$(CONFIG_ZRAM) += zram/ obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/ diff --git a/drivers/staging/sep/Kconfig b/drivers/staging/sep/Kconfig deleted file mode 100644 index 0a9c39c..0000000 --- a/drivers/staging/sep/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config DX_SEP - tristate "Discretix SEP driver" -# depends on MRST - depends on RAR_REGISTER && PCI - default y - help - Discretix SEP driver - - If unsure say M. The compiled module will be - called sep_driver.ko diff --git a/drivers/staging/sep/Makefile b/drivers/staging/sep/Makefile deleted file mode 100644 index 628d5f9..0000000 --- a/drivers/staging/sep/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -obj-$(CONFIG_DX_SEP) := sep_driver.o - diff --git a/drivers/staging/sep/TODO b/drivers/staging/sep/TODO deleted file mode 100644 index ff0e931..0000000 --- a/drivers/staging/sep/TODO +++ /dev/null @@ -1,8 +0,0 @@ -Todo's so far (from Alan Cox) -- Fix firmware loading -- Get firmware into firmware git tree -- Review and tidy each algorithm function -- Check whether it can be plugged into any of the kernel crypto API - interfaces -- Do something about the magic shared memory interface and replace it - with something saner (in Linux terms) diff --git a/drivers/staging/sep/sep_dev.h b/drivers/staging/sep/sep_dev.h deleted file mode 100644 index 9200524..0000000 --- a/drivers/staging/sep/sep_dev.h +++ /dev/null @@ -1,110 +0,0 @@ -#ifndef __SEP_DEV_H__ -#define __SEP_DEV_H__ - -/* - * - * sep_dev.h - Security Processor Device Structures - * - * Copyright(c) 2009 Intel Corporation. All rights reserved. - * Copyright(c) 2009 Discretix. 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 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. - * - * CONTACTS: - * - * Alan Cox alan@linux.intel.com - * - */ - -struct sep_device { - /* pointer to pci dev */ - struct pci_dev *pdev; - - unsigned long in_use; - - /* address of the shared memory allocated during init for SEP driver - (coherent alloc) */ - void *shared_addr; - /* the physical address of the shared area */ - dma_addr_t shared_bus; - - /* restricted access region (coherent alloc) */ - dma_addr_t rar_bus; - void *rar_addr; - /* firmware regions: cache is at rar_addr */ - unsigned long cache_size; - - /* follows the cache */ - dma_addr_t resident_bus; - unsigned long resident_size; - void *resident_addr; - - /* start address of the access to the SEP registers from driver */ - void __iomem *reg_addr; - /* transaction counter that coordinates the transactions between SEP and HOST */ - unsigned long send_ct; - /* counter for the messages from sep */ - unsigned long reply_ct; - /* counter for the number of bytes allocated in the pool for the current - transaction */ - unsigned long data_pool_bytes_allocated; - - /* array of pointers to the pages that represent input data for the synchronic - DMA action */ - struct page **in_page_array; - - /* array of pointers to the pages that represent out data for the synchronic - DMA action */ - struct page **out_page_array; - - /* number of pages in the sep_in_page_array */ - unsigned long in_num_pages; - - /* number of pages in the sep_out_page_array */ - unsigned long out_num_pages; - - /* global data for every flow */ - struct sep_flow_context_t flows[SEP_DRIVER_NUM_FLOWS]; - - /* pointer to the workqueue that handles the flow done interrupts */ - struct workqueue_struct *flow_wq; - -}; - -static struct sep_device *sep_dev; - -static inline void sep_write_reg(struct sep_device *dev, int reg, u32 value) -{ - void __iomem *addr = dev->reg_addr + reg; - writel(value, addr); -} - -static inline u32 sep_read_reg(struct sep_device *dev, int reg) -{ - void __iomem *addr = dev->reg_addr + reg; - return readl(addr); -} - -/* wait for SRAM write complete(indirect write */ -static inline void sep_wait_sram_write(struct sep_device *dev) -{ - u32 reg_val; - do - reg_val = sep_read_reg(dev, HW_SRAM_DATA_READY_REG_ADDR); - while (!(reg_val & 1)); -} - - -#endif diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c deleted file mode 100644 index ecbde34..0000000 --- a/drivers/staging/sep/sep_driver.c +++ /dev/null @@ -1,2742 +0,0 @@ -/* - * - * sep_driver.c - Security Processor Driver main group of functions - * - * Copyright(c) 2009 Intel Corporation. All rights reserved. - * Copyright(c) 2009 Discretix. 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 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. - * - * CONTACTS: - * - * Mark Allyn mark.a.allyn@intel.com - * - * CHANGES: - * - * 2009.06.26 Initial publish - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sep_driver_hw_defs.h" -#include "sep_driver_config.h" -#include "sep_driver_api.h" -#include "sep_dev.h" - -#if SEP_DRIVER_ARM_DEBUG_MODE - -#define CRYS_SEP_ROM_length 0x4000 -#define CRYS_SEP_ROM_start_address 0x8000C000UL -#define CRYS_SEP_ROM_start_address_offset 0xC000UL -#define SEP_ROM_BANK_register 0x80008420UL -#define SEP_ROM_BANK_register_offset 0x8420UL -#define SEP_RAR_IO_MEM_REGION_START_ADDRESS 0x82000000 - -/* - * THESE 2 definitions are specific to the board - must be - * defined during integration - */ -#define SEP_RAR_IO_MEM_REGION_START_ADDRESS 0xFF0D0000 - -/* 2M size */ - -static void sep_load_rom_code(struct sep_device *sep) -{ - /* Index variables */ - unsigned long i, k, j; - u32 reg; - u32 error; - u32 warning; - - /* Loading ROM from SEP_ROM_image.h file */ - k = sizeof(CRYS_SEP_ROM); - - edbg("SEP Driver: DX_CC_TST_SepRomLoader start\n"); - - edbg("SEP Driver: k is %lu\n", k); - edbg("SEP Driver: sep->reg_addr is %p\n", sep->reg_addr); - edbg("SEP Driver: CRYS_SEP_ROM_start_address_offset is %p\n", CRYS_SEP_ROM_start_address_offset); - - for (i = 0; i < 4; i++) { - /* write bank */ - sep_write_reg(sep, SEP_ROM_BANK_register_offset, i); - - for (j = 0; j < CRYS_SEP_ROM_length / 4; j++) { - sep_write_reg(sep, CRYS_SEP_ROM_start_address_offset + 4 * j, CRYS_SEP_ROM[i * 0x1000 + j]); - - k = k - 4; - - if (k == 0) { - j = CRYS_SEP_ROM_length; - i = 4; - } - } - } - - /* reset the SEP */ - sep_write_reg(sep, HW_HOST_SEP_SW_RST_REG_ADDR, 0x1); - - /* poll for SEP ROM boot finish */ - do - reg = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR); - while (!reg); - - edbg("SEP Driver: ROM polling ended\n"); - - switch (reg) { - case 0x1: - /* fatal error - read erro status from GPRO */ - error = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR0_REG_ADDR); - edbg("SEP Driver: ROM polling case 1\n"); - break; - case 0x4: - /* Cold boot ended successfully */ - case 0x8: - /* Warmboot ended successfully */ - case 0x10: - /* ColdWarm boot ended successfully */ - error = 0; - case 0x2: - /* Boot First Phase ended */ - warning = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR0_REG_ADDR); - case 0x20: - edbg("SEP Driver: ROM polling case %d\n", reg); - break; - } - -} - -#else -static void sep_load_rom_code(struct sep_device *sep) { } -#endif /* SEP_DRIVER_ARM_DEBUG_MODE */ - - - -/*---------------------------------------- - DEFINES ------------------------------------------*/ - -#define BASE_ADDRESS_FOR_SYSTEM 0xfffc0000 -#define SEP_RAR_IO_MEM_REGION_SIZE 0x40000 - -/*-------------------------------------------- - GLOBAL variables ---------------------------------------------*/ - -/* debug messages level */ -static int debug; -module_param(debug, int , 0); -MODULE_PARM_DESC(debug, "Flag to enable SEP debug messages"); - -/* Keep this a single static object for now to keep the conversion easy */ - -static struct sep_device sep_instance; -static struct sep_device *sep_dev = &sep_instance; - -/* - mutex for the access to the internals of the sep driver -*/ -static DEFINE_MUTEX(sep_mutex); - - -/* wait queue head (event) of the driver */ -static DECLARE_WAIT_QUEUE_HEAD(sep_event); - -/** - * sep_load_firmware - copy firmware cache/resident - * @sep: device we are loading - * - * This functions copies the cache and resident from their source - * location into destination shared memory. - */ - -static int sep_load_firmware(struct sep_device *sep) -{ - const struct firmware *fw; - char *cache_name = "sep/cache.image.bin"; - char *res_name = "sep/resident.image.bin"; - int error; - - edbg("SEP Driver:rar_virtual is %p\n", sep->rar_addr); - edbg("SEP Driver:rar_bus is %08llx\n", (unsigned long long)sep->rar_bus); - - /* load cache */ - error = request_firmware(&fw, cache_name, &sep->pdev->dev); - if (error) { - edbg("SEP Driver:cant request cache fw\n"); - return error; - } - edbg("SEP Driver:cache %08Zx@%p\n", fw->size, (void *) fw->data); - - memcpy(sep->rar_addr, (void *)fw->data, fw->size); - sep->cache_size = fw->size; - release_firmware(fw); - - sep->resident_bus = sep->rar_bus + sep->cache_size; - sep->resident_addr = sep->rar_addr + sep->cache_size; - - /* load resident */ - error = request_firmware(&fw, res_name, &sep->pdev->dev); - if (error) { - edbg("SEP Driver:cant request res fw\n"); - return error; - } - edbg("sep: res %08Zx@%p\n", fw->size, (void *)fw->data); - - memcpy(sep->resident_addr, (void *) fw->data, fw->size); - sep->resident_size = fw->size; - release_firmware(fw); - - edbg("sep: resident v %p b %08llx cache v %p b %08llx\n", - sep->resident_addr, (unsigned long long)sep->resident_bus, - sep->rar_addr, (unsigned long long)sep->rar_bus); - return 0; -} - -MODULE_FIRMWARE("sep/cache.image.bin"); -MODULE_FIRMWARE("sep/resident.image.bin"); - -/** - * sep_map_and_alloc_shared_area - allocate shared block - * @sep: security processor - * @size: size of shared area - * - * Allocate a shared buffer in host memory that can be used by both the - * kernel and also the hardware interface via DMA. - */ - -static int sep_map_and_alloc_shared_area(struct sep_device *sep, - unsigned long size) -{ - /* shared_addr = ioremap_nocache(0xda00000,shared_area_size); */ - sep->shared_addr = dma_alloc_coherent(&sep->pdev->dev, size, - &sep->shared_bus, GFP_KERNEL); - - if (!sep->shared_addr) { - edbg("sep_driver :shared memory dma_alloc_coherent failed\n"); - return -ENOMEM; - } - /* set the bus address of the shared area */ - edbg("sep: shared_addr %ld bytes @%p (bus %08llx)\n", - size, sep->shared_addr, (unsigned long long)sep->shared_bus); - return 0; -} - -/** - * sep_unmap_and_free_shared_area - free shared block - * @sep: security processor - * - * Free the shared area allocated to the security processor. The - * processor must have finished with this and any final posted - * writes cleared before we do so. - */ -static void sep_unmap_and_free_shared_area(struct sep_device *sep, int size) -{ - dma_free_coherent(&sep->pdev->dev, size, - sep->shared_addr, sep->shared_bus); -} - -/** - * sep_shared_virt_to_bus - convert bus/virt addresses - * - * Returns the bus address inside the shared area according - * to the virtual address. - */ - -static dma_addr_t sep_shared_virt_to_bus(struct sep_device *sep, - void *virt_address) -{ - dma_addr_t pa = sep->shared_bus + (virt_address - sep->shared_addr); - edbg("sep: virt to bus b %08llx v %p\n", (unsigned long long) pa, - virt_address); - return pa; -} - -/** - * sep_shared_bus_to_virt - convert bus/virt addresses - * - * Returns virtual address inside the shared area according - * to the bus address. - */ - -static void *sep_shared_bus_to_virt(struct sep_device *sep, - dma_addr_t bus_address) -{ - return sep->shared_addr + (bus_address - sep->shared_bus); -} - - -/** - * sep_try_open - attempt to open a SEP device - * @sep: device to attempt to open - * - * Atomically attempt to get ownership of a SEP device. - * Returns 1 if the device was opened, 0 on failure. - */ - -static int sep_try_open(struct sep_device *sep) -{ - if (!test_and_set_bit(0, &sep->in_use)) - return 1; - return 0; -} - -/** - * sep_open - device open method - * @inode: inode of sep device - * @filp: file handle to sep device - * - * Open method for the SEP device. Called when userspace opens - * the SEP device node. Must also release the memory data pool - * allocations. - * - * Returns zero on success otherwise an error code. - */ - -static int sep_open(struct inode *inode, struct file *filp) -{ - if (sep_dev == NULL) - return -ENODEV; - - /* check the blocking mode */ - if (filp->f_flags & O_NDELAY) { - if (sep_try_open(sep_dev) == 0) - return -EAGAIN; - } else - if (wait_event_interruptible(sep_event, sep_try_open(sep_dev)) < 0) - return -EINTR; - - /* Bind to the device, we only have one which makes it easy */ - filp->private_data = sep_dev; - /* release data pool allocations */ - sep_dev->data_pool_bytes_allocated = 0; - return 0; -} - - -/** - * sep_release - close a SEP device - * @inode: inode of SEP device - * @filp: file handle being closed - * - * Called on the final close of a SEP device. As the open protects against - * multiple simultaenous opens that means this method is called when the - * final reference to the open handle is dropped. - */ - -static int sep_release(struct inode *inode, struct file *filp) -{ - struct sep_device *sep = filp->private_data; -#if 0 /*!SEP_DRIVER_POLLING_MODE */ - /* close IMR */ - sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, 0x7FFF); - /* release IRQ line */ - free_irq(SEP_DIRVER_IRQ_NUM, sep); - -#endif - /* Ensure any blocked open progresses */ - clear_bit(0, &sep->in_use); - wake_up(&sep_event); - return 0; -} - -/*--------------------------------------------------------------- - map function - this functions maps the message shared area ------------------------------------------------------------------*/ -static int sep_mmap(struct file *filp, struct vm_area_struct *vma) -{ - dma_addr_t bus_addr; - struct sep_device *sep = filp->private_data; - - dbg("-------->SEP Driver: mmap start\n"); - - /* check that the size of the mapped range is as the size of the message - shared area */ - if ((vma->vm_end - vma->vm_start) > SEP_DRIVER_MMMAP_AREA_SIZE) { - edbg("SEP Driver mmap requested size is more than allowed\n"); - printk(KERN_WARNING "SEP Driver mmap requested size is more than allowed\n"); - printk(KERN_WARNING "SEP Driver vma->vm_end is %08lx\n", vma->vm_end); - printk(KERN_WARNING "SEP Driver vma->vm_end is %08lx\n", vma->vm_start); - return -EAGAIN; - } - - edbg("SEP Driver:sep->shared_addr is %p\n", sep->shared_addr); - - /* get bus address */ - bus_addr = sep->shared_bus; - - edbg("SEP Driver: phys_addr is %08llx\n", (unsigned long long)bus_addr); - - if (remap_pfn_range(vma, vma->vm_start, bus_addr >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot)) { - edbg("SEP Driver remap_page_range failed\n"); - printk(KERN_WARNING "SEP Driver remap_page_range failed\n"); - return -EAGAIN; - } - - dbg("SEP Driver:<-------- mmap end\n"); - - return 0; -} - - -/*----------------------------------------------- - poll function -*----------------------------------------------*/ -static unsigned int sep_poll(struct file *filp, poll_table * wait) -{ - unsigned long count; - unsigned int mask = 0; - unsigned long retval = 0; /* flow id */ - struct sep_device *sep = filp->private_data; - - dbg("---------->SEP Driver poll: start\n"); - - -#if SEP_DRIVER_POLLING_MODE - - while (sep->send_ct != (retval & 0x7FFFFFFF)) { - retval = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR); - - for (count = 0; count < 10 * 4; count += 4) - edbg("Poll Debug Word %lu of the message is %lu\n", count, *((unsigned long *) (sep->shared_addr + SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES + count))); - } - - sep->reply_ct++; -#else - /* add the event to the polling wait table */ - poll_wait(filp, &sep_event, wait); - -#endif - - edbg("sep->send_ct is %lu\n", sep->send_ct); - edbg("sep->reply_ct is %lu\n", sep->reply_ct); - - /* check if the data is ready */ - if (sep->send_ct == sep->reply_ct) { - for (count = 0; count < 12 * 4; count += 4) - edbg("Sep Mesg Word %lu of the message is %lu\n", count, *((unsigned long *) (sep->shared_addr + count))); - - for (count = 0; count < 10 * 4; count += 4) - edbg("Debug Data Word %lu of the message is %lu\n", count, *((unsigned long *) (sep->shared_addr + 0x1800 + count))); - - retval = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR); - edbg("retval is %lu\n", retval); - /* check if the this is sep reply or request */ - if (retval >> 31) { - edbg("SEP Driver: sep request in\n"); - /* request */ - mask |= POLLOUT | POLLWRNORM; - } else { - edbg("SEP Driver: sep reply in\n"); - mask |= POLLIN | POLLRDNORM; - } - } - dbg("SEP Driver:<-------- poll exit\n"); - return mask; -} - -/** - * sep_time_address - address in SEP memory of time - * @sep: SEP device we want the address from - * - * Return the address of the two dwords in memory used for time - * setting. - */ - -static u32 *sep_time_address(struct sep_device *sep) -{ - return sep->shared_addr + SEP_DRIVER_SYSTEM_TIME_MEMORY_OFFSET_IN_BYTES; -} - -/** - * sep_set_time - set the SEP time - * @sep: the SEP we are setting the time for - * - * Calculates time and sets it at the predefined address. - * Called with the sep mutex held. - */ -static unsigned long sep_set_time(struct sep_device *sep) -{ - struct timeval time; - u32 *time_addr; /* address of time as seen by the kernel */ - - - dbg("sep:sep_set_time start\n"); - - do_gettimeofday(&time); - - /* set value in the SYSTEM MEMORY offset */ - time_addr = sep_time_address(sep); - - time_addr[0] = SEP_TIME_VAL_TOKEN; - time_addr[1] = time.tv_sec; - - edbg("SEP Driver:time.tv_sec is %lu\n", time.tv_sec); - edbg("SEP Driver:time_addr is %p\n", time_addr); - edbg("SEP Driver:sep->shared_addr is %p\n", sep->shared_addr); - - return time.tv_sec; -} - -/** - * sep_dump_message - dump the message that is pending - * @sep: sep device - * - * Dump out the message pending in the shared message area - */ - -static void sep_dump_message(struct sep_device *sep) -{ - int count; - for (count = 0; count < 12 * 4; count += 4) - edbg("Word %d of the message is %u\n", count, *((u32 *) (sep->shared_addr + count))); -} - -/** - * sep_send_command_handler - kick off a command - * @sep: sep being signalled - * - * This function raises interrupt to SEP that signals that is has a new - * command from the host - */ - -static void sep_send_command_handler(struct sep_device *sep) -{ - dbg("sep:sep_send_command_handler start\n"); - - mutex_lock(&sep_mutex); - sep_set_time(sep); - - /* FIXME: flush cache */ - flush_cache_all(); - - sep_dump_message(sep); - /* update counter */ - sep->send_ct++; - /* send interrupt to SEP */ - sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x2); - dbg("SEP Driver:<-------- sep_send_command_handler end\n"); - mutex_unlock(&sep_mutex); - return; -} - -/** - * sep_send_reply_command_handler - kick off a command reply - * @sep: sep being signalled - * - * This function raises interrupt to SEP that signals that is has a new - * command from the host - */ - -static void sep_send_reply_command_handler(struct sep_device *sep) -{ - dbg("sep:sep_send_reply_command_handler start\n"); - - /* flash cache */ - flush_cache_all(); - - sep_dump_message(sep); - - mutex_lock(&sep_mutex); - sep->send_ct++; /* update counter */ - /* send the interrupt to SEP */ - sep_write_reg(sep, HW_HOST_HOST_SEP_GPR2_REG_ADDR, sep->send_ct); - /* update both counters */ - sep->send_ct++; - sep->reply_ct++; - mutex_unlock(&sep_mutex); - dbg("sep: sep_send_reply_command_handler end\n"); -} - -/* - This function handles the allocate data pool memory request - This function returns calculates the bus address of the - allocated memory, and the offset of this area from the mapped address. - Therefore, the FVOs in user space can calculate the exact virtual - address of this allocated memory -*/ -static int sep_allocate_data_pool_memory_handler(struct sep_device *sep, - unsigned long arg) -{ - int error; - struct sep_driver_alloc_t command_args; - - dbg("SEP Driver:--------> sep_allocate_data_pool_memory_handler start\n"); - - error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_alloc_t)); - if (error) { - error = -EFAULT; - goto end_function; - } - - /* allocate memory */ - if ((sep->data_pool_bytes_allocated + command_args.num_bytes) > SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES) { - error = -ENOMEM; - goto end_function; - } - - /* set the virtual and bus address */ - command_args.offset = SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES + sep->data_pool_bytes_allocated; - command_args.phys_address = sep->shared_bus + SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES + sep->data_pool_bytes_allocated; - - /* write the memory back to the user space */ - error = copy_to_user((void *) arg, (void *) &command_args, sizeof(struct sep_driver_alloc_t)); - if (error) { - error = -EFAULT; - goto end_function; - } - - /* set the allocation */ - sep->data_pool_bytes_allocated += command_args.num_bytes; - -end_function: - dbg("SEP Driver:<-------- sep_allocate_data_pool_memory_handler end\n"); - return error; -} - -/* - This function handles write into allocated data pool command -*/ -static int sep_write_into_data_pool_handler(struct sep_device *sep, unsigned long arg) -{ - int error; - void *virt_address; - unsigned long va; - unsigned long app_in_address; - unsigned long num_bytes; - void *data_pool_area_addr; - - dbg("SEP Driver:--------> sep_write_into_data_pool_handler start\n"); - - /* get the application address */ - error = get_user(app_in_address, &(((struct sep_driver_write_t *) arg)->app_address)); - if (error) - goto end_function; - - /* get the virtual kernel address address */ - error = get_user(va, &(((struct sep_driver_write_t *) arg)->datapool_address)); - if (error) - goto end_function; - virt_address = (void *)va; - - /* get the number of bytes */ - error = get_user(num_bytes, &(((struct sep_driver_write_t *) arg)->num_bytes)); - if (error) - goto end_function; - - /* calculate the start of the data pool */ - data_pool_area_addr = sep->shared_addr + SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES; - - - /* check that the range of the virtual kernel address is correct */ - if (virt_address < data_pool_area_addr || virt_address > (data_pool_area_addr + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES)) { - error = -EINVAL; - goto end_function; - } - /* copy the application data */ - error = copy_from_user(virt_address, (void *) app_in_address, num_bytes); - if (error) - error = -EFAULT; -end_function: - dbg("SEP Driver:<-------- sep_write_into_data_pool_handler end\n"); - return error; -} - -/* - this function handles the read from data pool command -*/ -static int sep_read_from_data_pool_handler(struct sep_device *sep, unsigned long arg) -{ - int error; - /* virtual address of dest application buffer */ - unsigned long app_out_address; - /* virtual address of the data pool */ - unsigned long va; - void *virt_address; - unsigned long num_bytes; - void *data_pool_area_addr; - - dbg("SEP Driver:--------> sep_read_from_data_pool_handler start\n"); - - /* get the application address */ - error = get_user(app_out_address, &(((struct sep_driver_write_t *) arg)->app_address)); - if (error) - goto end_function; - - /* get the virtual kernel address address */ - error = get_user(va, &(((struct sep_driver_write_t *) arg)->datapool_address)); - if (error) - goto end_function; - virt_address = (void *)va; - - /* get the number of bytes */ - error = get_user(num_bytes, &(((struct sep_driver_write_t *) arg)->num_bytes)); - if (error) - goto end_function; - - /* calculate the start of the data pool */ - data_pool_area_addr = sep->shared_addr + SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES; - - /* FIXME: These are incomplete all over the driver: what about + len - and when doing that also overflows */ - /* check that the range of the virtual kernel address is correct */ - if (virt_address < data_pool_area_addr || virt_address > data_pool_area_addr + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES) { - error = -EINVAL; - goto end_function; - } - - /* copy the application data */ - error = copy_to_user((void *) app_out_address, virt_address, num_bytes); - if (error) - error = -EFAULT; -end_function: - dbg("SEP Driver:<-------- sep_read_from_data_pool_handler end\n"); - return error; -} - -/* - This function releases all the application virtual buffer physical pages, - that were previously locked -*/ -static int sep_free_dma_pages(struct page **page_array_ptr, unsigned long num_pages, unsigned long dirtyFlag) -{ - unsigned long count; - - if (dirtyFlag) { - for (count = 0; count < num_pages; count++) { - /* the out array was written, therefore the data was changed */ - if (!PageReserved(page_array_ptr[count])) - SetPageDirty(page_array_ptr[count]); - page_cache_release(page_array_ptr[count]); - } - } else { - /* free in pages - the data was only read, therefore no update was done - on those pages */ - for (count = 0; count < num_pages; count++) - page_cache_release(page_array_ptr[count]); - } - - if (page_array_ptr) - /* free the array */ - kfree(page_array_ptr); - - return 0; -} - -/* - This function locks all the physical pages of the kernel virtual buffer - and construct a basic lli array, where each entry holds the physical - page address and the size that application data holds in this physical pages -*/ -static int sep_lock_kernel_pages(struct sep_device *sep, - unsigned long kernel_virt_addr, - unsigned long data_size, - unsigned long *num_pages_ptr, - struct sep_lli_entry_t **lli_array_ptr, - struct page ***page_array_ptr) -{ - int error = 0; - /* the the page of the end address of the user space buffer */ - unsigned long end_page; - /* the page of the start address of the user space buffer */ - unsigned long start_page; - /* the range in pages */ - unsigned long num_pages; - struct sep_lli_entry_t *lli_array; - /* next kernel address to map */ - unsigned long next_kernel_address; - unsigned long count; - - dbg("SEP Driver:--------> sep_lock_kernel_pages start\n"); - - /* set start and end pages and num pages */ - end_page = (kernel_virt_addr + data_size - 1) >> PAGE_SHIFT; - start_page = kernel_virt_addr >> PAGE_SHIFT; - num_pages = end_page - start_page + 1; - - edbg("SEP Driver: kernel_virt_addr is %08lx\n", kernel_virt_addr); - edbg("SEP Driver: data_size is %lu\n", data_size); - edbg("SEP Driver: start_page is %lx\n", start_page); - edbg("SEP Driver: end_page is %lx\n", end_page); - edbg("SEP Driver: num_pages is %lu\n", num_pages); - - lli_array = kmalloc(sizeof(struct sep_lli_entry_t) * num_pages, GFP_ATOMIC); - if (!lli_array) { - edbg("SEP Driver: kmalloc for lli_array failed\n"); - error = -ENOMEM; - goto end_function; - } - - /* set the start address of the first page - app data may start not at - the beginning of the page */ - lli_array[0].physical_address = (unsigned long) virt_to_phys((unsigned long *) kernel_virt_addr); - - /* check that not all the data is in the first page only */ - if ((PAGE_SIZE - (kernel_virt_addr & (~PAGE_MASK))) >= data_size) - lli_array[0].block_size = data_size; - else - lli_array[0].block_size = PAGE_SIZE - (kernel_virt_addr & (~PAGE_MASK)); - - /* debug print */ - dbg("lli_array[0].physical_address is %08lx, lli_array[0].block_size is %lu\n", lli_array[0].physical_address, lli_array[0].block_size); - - /* advance the address to the start of the next page */ - next_kernel_address = (kernel_virt_addr & PAGE_MASK) + PAGE_SIZE; - - /* go from the second page to the prev before last */ - for (count = 1; count < (num_pages - 1); count++) { - lli_array[count].physical_address = (unsigned long) virt_to_phys((unsigned long *) next_kernel_address); - lli_array[count].block_size = PAGE_SIZE; - - edbg("lli_array[%lu].physical_address is %08lx, lli_array[%lu].block_size is %lu\n", count, lli_array[count].physical_address, count, lli_array[count].block_size); - next_kernel_address += PAGE_SIZE; - } - - /* if more then 1 pages locked - then update for the last page size needed */ - if (num_pages > 1) { - /* update the address of the last page */ - lli_array[count].physical_address = (unsigned long) virt_to_phys((unsigned long *) next_kernel_address); - - /* set the size of the last page */ - lli_array[count].block_size = (kernel_virt_addr + data_size) & (~PAGE_MASK); - - if (lli_array[count].block_size == 0) { - dbg("app_virt_addr is %08lx\n", kernel_virt_addr); - dbg("data_size is %lu\n", data_size); - while (1); - } - - edbg("lli_array[%lu].physical_address is %08lx, lli_array[%lu].block_size is %lu\n", count, lli_array[count].physical_address, count, lli_array[count].block_size); - } - /* set output params */ - *lli_array_ptr = lli_array; - *num_pages_ptr = num_pages; - *page_array_ptr = 0; -end_function: - dbg("SEP Driver:<-------- sep_lock_kernel_pages end\n"); - return 0; -} - -/* - This function locks all the physical pages of the application virtual buffer - and construct a basic lli array, where each entry holds the physical page - address and the size that application data holds in this physical pages -*/ -static int sep_lock_user_pages(struct sep_device *sep, - unsigned long app_virt_addr, - unsigned long data_size, - unsigned long *num_pages_ptr, - struct sep_lli_entry_t **lli_array_ptr, - struct page ***page_array_ptr) -{ - int error = 0; - /* the the page of the end address of the user space buffer */ - unsigned long end_page; - /* the page of the start address of the user space buffer */ - unsigned long start_page; - /* the range in pages */ - unsigned long num_pages; - struct page **page_array; - struct sep_lli_entry_t *lli_array; - unsigned long count; - int result; - - dbg("SEP Driver:--------> sep_lock_user_pages start\n"); - - /* set start and end pages and num pages */ - end_page = (app_virt_addr + data_size - 1) >> PAGE_SHIFT; - start_page = app_virt_addr >> PAGE_SHIFT; - num_pages = end_page - start_page + 1; - - edbg("SEP Driver: app_virt_addr is %08lx\n", app_virt_addr); - edbg("SEP Driver: data_size is %lu\n", data_size); - edbg("SEP Driver: start_page is %lu\n", start_page); - edbg("SEP Driver: end_page is %lu\n", end_page); - edbg("SEP Driver: num_pages is %lu\n", num_pages); - - /* allocate array of pages structure pointers */ - page_array = kmalloc(sizeof(struct page *) * num_pages, GFP_ATOMIC); - if (!page_array) { - edbg("SEP Driver: kmalloc for page_array failed\n"); - - error = -ENOMEM; - goto end_function; - } - - lli_array = kmalloc(sizeof(struct sep_lli_entry_t) * num_pages, GFP_ATOMIC); - if (!lli_array) { - edbg("SEP Driver: kmalloc for lli_array failed\n"); - - error = -ENOMEM; - goto end_function_with_error1; - } - - /* convert the application virtual address into a set of physical */ - down_read(¤t->mm->mmap_sem); - result = get_user_pages(current, current->mm, app_virt_addr, num_pages, 1, 0, page_array, 0); - up_read(¤t->mm->mmap_sem); - - /* check the number of pages locked - if not all then exit with error */ - if (result != num_pages) { - dbg("SEP Driver: not all pages locked by get_user_pages\n"); - - error = -ENOMEM; - goto end_function_with_error2; - } - - /* flush the cache */ - for (count = 0; count < num_pages; count++) - flush_dcache_page(page_array[count]); - - /* set the start address of the first page - app data may start not at - the beginning of the page */ - lli_array[0].physical_address = ((unsigned long) page_to_phys(page_array[0])) + (app_virt_addr & (~PAGE_MASK)); - - /* check that not all the data is in the first page only */ - if ((PAGE_SIZE - (app_virt_addr & (~PAGE_MASK))) >= data_size) - lli_array[0].block_size = data_size; - else - lli_array[0].block_size = PAGE_SIZE - (app_virt_addr & (~PAGE_MASK)); - - /* debug print */ - dbg("lli_array[0].physical_address is %08lx, lli_array[0].block_size is %lu\n", lli_array[0].physical_address, lli_array[0].block_size); - - /* go from the second page to the prev before last */ - for (count = 1; count < (num_pages - 1); count++) { - lli_array[count].physical_address = (unsigned long) page_to_phys(page_array[count]); - lli_array[count].block_size = PAGE_SIZE; - - edbg("lli_array[%lu].physical_address is %08lx, lli_array[%lu].block_size is %lu\n", count, lli_array[count].physical_address, count, lli_array[count].block_size); - } - - /* if more then 1 pages locked - then update for the last page size needed */ - if (num_pages > 1) { - /* update the address of the last page */ - lli_array[count].physical_address = (unsigned long) page_to_phys(page_array[count]); - - /* set the size of the last page */ - lli_array[count].block_size = (app_virt_addr + data_size) & (~PAGE_MASK); - - if (lli_array[count].block_size == 0) { - dbg("app_virt_addr is %08lx\n", app_virt_addr); - dbg("data_size is %lu\n", data_size); - while (1); - } - edbg("lli_array[%lu].physical_address is %08lx, lli_array[%lu].block_size is %lu\n", - count, lli_array[count].physical_address, - count, lli_array[count].block_size); - } - - /* set output params */ - *lli_array_ptr = lli_array; - *num_pages_ptr = num_pages; - *page_array_ptr = page_array; - goto end_function; - -end_function_with_error2: - /* release the cache */ - for (count = 0; count < num_pages; count++) - page_cache_release(page_array[count]); - kfree(lli_array); -end_function_with_error1: - kfree(page_array); -end_function: - dbg("SEP Driver:<-------- sep_lock_user_pages end\n"); - return 0; -} - - -/* - this function calculates the size of data that can be inserted into the lli - table from this array the condition is that either the table is full - (all etnries are entered), or there are no more entries in the lli array -*/ -static unsigned long sep_calculate_lli_table_max_size(struct sep_lli_entry_t *lli_in_array_ptr, unsigned long num_array_entries) -{ - unsigned long table_data_size = 0; - unsigned long counter; - - /* calculate the data in the out lli table if till we fill the whole - table or till the data has ended */ - for (counter = 0; (counter < (SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP - 1)) && (counter < num_array_entries); counter++) - table_data_size += lli_in_array_ptr[counter].block_size; - return table_data_size; -} - -/* - this functions builds ont lli table from the lli_array according to - the given size of data -*/ -static void sep_build_lli_table(struct sep_lli_entry_t *lli_array_ptr, struct sep_lli_entry_t *lli_table_ptr, unsigned long *num_processed_entries_ptr, unsigned long *num_table_entries_ptr, unsigned long table_data_size) -{ - unsigned long curr_table_data_size; - /* counter of lli array entry */ - unsigned long array_counter; - - dbg("SEP Driver:--------> sep_build_lli_table start\n"); - - /* init currrent table data size and lli array entry counter */ - curr_table_data_size = 0; - array_counter = 0; - *num_table_entries_ptr = 1; - - edbg("SEP Driver:table_data_size is %lu\n", table_data_size); - - /* fill the table till table size reaches the needed amount */ - while (curr_table_data_size < table_data_size) { - /* update the number of entries in table */ - (*num_table_entries_ptr)++; - - lli_table_ptr->physical_address = lli_array_ptr[array_counter].physical_address; - lli_table_ptr->block_size = lli_array_ptr[array_counter].block_size; - curr_table_data_size += lli_table_ptr->block_size; - - edbg("SEP Driver:lli_table_ptr is %08lx\n", (unsigned long) lli_table_ptr); - edbg("SEP Driver:lli_table_ptr->physical_address is %08lx\n", lli_table_ptr->physical_address); - edbg("SEP Driver:lli_table_ptr->block_size is %lu\n", lli_table_ptr->block_size); - - /* check for overflow of the table data */ - if (curr_table_data_size > table_data_size) { - edbg("SEP Driver:curr_table_data_size > table_data_size\n"); - - /* update the size of block in the table */ - lli_table_ptr->block_size -= (curr_table_data_size - table_data_size); - - /* update the physical address in the lli array */ - lli_array_ptr[array_counter].physical_address += lli_table_ptr->block_size; - - /* update the block size left in the lli array */ - lli_array_ptr[array_counter].block_size = (curr_table_data_size - table_data_size); - } else - /* advance to the next entry in the lli_array */ - array_counter++; - - edbg("SEP Driver:lli_table_ptr->physical_address is %08lx\n", lli_table_ptr->physical_address); - edbg("SEP Driver:lli_table_ptr->block_size is %lu\n", lli_table_ptr->block_size); - - /* move to the next entry in table */ - lli_table_ptr++; - } - - /* set the info entry to default */ - lli_table_ptr->physical_address = 0xffffffff; - lli_table_ptr->block_size = 0; - - edbg("SEP Driver:lli_table_ptr is %08lx\n", (unsigned long) lli_table_ptr); - edbg("SEP Driver:lli_table_ptr->physical_address is %08lx\n", lli_table_ptr->physical_address); - edbg("SEP Driver:lli_table_ptr->block_size is %lu\n", lli_table_ptr->block_size); - - /* set the output parameter */ - *num_processed_entries_ptr += array_counter; - - edbg("SEP Driver:*num_processed_entries_ptr is %lu\n", *num_processed_entries_ptr); - dbg("SEP Driver:<-------- sep_build_lli_table end\n"); - return; -} - -/* - this function goes over the list of the print created tables and - prints all the data -*/ -static void sep_debug_print_lli_tables(struct sep_device *sep, struct sep_lli_entry_t *lli_table_ptr, unsigned long num_table_entries, unsigned long table_data_size) -{ - unsigned long table_count; - unsigned long entries_count; - - dbg("SEP Driver:--------> sep_debug_print_lli_tables start\n"); - - table_count = 1; - while ((unsigned long) lli_table_ptr != 0xffffffff) { - edbg("SEP Driver: lli table %08lx, table_data_size is %lu\n", table_count, table_data_size); - edbg("SEP Driver: num_table_entries is %lu\n", num_table_entries); - - /* print entries of the table (without info entry) */ - for (entries_count = 0; entries_count < num_table_entries; entries_count++, lli_table_ptr++) { - edbg("SEP Driver:lli_table_ptr address is %08lx\n", (unsigned long) lli_table_ptr); - edbg("SEP Driver:phys address is %08lx block size is %lu\n", lli_table_ptr->physical_address, lli_table_ptr->block_size); - } - - /* point to the info entry */ - lli_table_ptr--; - - edbg("SEP Driver:phys lli_table_ptr->block_size is %lu\n", lli_table_ptr->block_size); - edbg("SEP Driver:phys lli_table_ptr->physical_address is %08lx\n", lli_table_ptr->physical_address); - - - table_data_size = lli_table_ptr->block_size & 0xffffff; - num_table_entries = (lli_table_ptr->block_size >> 24) & 0xff; - lli_table_ptr = (struct sep_lli_entry_t *) - (lli_table_ptr->physical_address); - - edbg("SEP Driver:phys table_data_size is %lu num_table_entries is %lu lli_table_ptr is%lu\n", table_data_size, num_table_entries, (unsigned long) lli_table_ptr); - - if ((unsigned long) lli_table_ptr != 0xffffffff) - lli_table_ptr = (struct sep_lli_entry_t *) sep_shared_bus_to_virt(sep, (unsigned long) lli_table_ptr); - - table_count++; - } - dbg("SEP Driver:<-------- sep_debug_print_lli_tables end\n"); -} - - -/* - This function prepares only input DMA table for synhronic symmetric - operations (HASH) -*/ -static int sep_prepare_input_dma_table(struct sep_device *sep, - unsigned long app_virt_addr, - unsigned long data_size, - unsigned long block_size, - unsigned long *lli_table_ptr, - unsigned long *num_entries_ptr, - unsigned long *table_data_size_ptr, - bool isKernelVirtualAddress) -{ - /* pointer to the info entry of the table - the last entry */ - struct sep_lli_entry_t *info_entry_ptr; - /* array of pointers ot page */ - struct sep_lli_entry_t *lli_array_ptr; - /* points to the first entry to be processed in the lli_in_array */ - unsigned long current_entry; - /* num entries in the virtual buffer */ - unsigned long sep_lli_entries; - /* lli table pointer */ - struct sep_lli_entry_t *in_lli_table_ptr; - /* the total data in one table */ - unsigned long table_data_size; - /* number of entries in lli table */ - unsigned long num_entries_in_table; - /* next table address */ - void *lli_table_alloc_addr; - unsigned long result; - - dbg("SEP Driver:--------> sep_prepare_input_dma_table start\n"); - - edbg("SEP Driver:data_size is %lu\n", data_size); - edbg("SEP Driver:block_size is %lu\n", block_size); - - /* initialize the pages pointers */ - sep->in_page_array = 0; - sep->in_num_pages = 0; - - if (data_size == 0) { - /* special case - created 2 entries table with zero data */ - in_lli_table_ptr = (struct sep_lli_entry_t *) (sep->shared_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES); - /* FIXME: Should the entry below not be for _bus */ - in_lli_table_ptr->physical_address = (unsigned long)sep->shared_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES; - in_lli_table_ptr->block_size = 0; - - in_lli_table_ptr++; - in_lli_table_ptr->physical_address = 0xFFFFFFFF; - in_lli_table_ptr->block_size = 0; - - *lli_table_ptr = sep->shared_bus + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES; - *num_entries_ptr = 2; - *table_data_size_ptr = 0; - - goto end_function; - } - - /* check if the pages are in Kernel Virtual Address layout */ - if (isKernelVirtualAddress == true) - /* lock the pages of the kernel buffer and translate them to pages */ - result = sep_lock_kernel_pages(sep, app_virt_addr, data_size, &sep->in_num_pages, &lli_array_ptr, &sep->in_page_array); - else - /* lock the pages of the user buffer and translate them to pages */ - result = sep_lock_user_pages(sep, app_virt_addr, data_size, &sep->in_num_pages, &lli_array_ptr, &sep->in_page_array); - - if (result) - return result; - - edbg("SEP Driver:output sep->in_num_pages is %lu\n", sep->in_num_pages); - - current_entry = 0; - info_entry_ptr = 0; - sep_lli_entries = sep->in_num_pages; - - /* initiate to point after the message area */ - lli_table_alloc_addr = sep->shared_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES; - - /* loop till all the entries in in array are not processed */ - while (current_entry < sep_lli_entries) { - /* set the new input and output tables */ - in_lli_table_ptr = (struct sep_lli_entry_t *) lli_table_alloc_addr; - - lli_table_alloc_addr += sizeof(struct sep_lli_entry_t) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP; - - /* calculate the maximum size of data for input table */ - table_data_size = sep_calculate_lli_table_max_size(&lli_array_ptr[current_entry], (sep_lli_entries - current_entry)); - - /* now calculate the table size so that it will be module block size */ - table_data_size = (table_data_size / block_size) * block_size; - - edbg("SEP Driver:output table_data_size is %lu\n", table_data_size); - - /* construct input lli table */ - sep_build_lli_table(&lli_array_ptr[current_entry], in_lli_table_ptr, ¤t_entry, &num_entries_in_table, table_data_size); - - if (info_entry_ptr == 0) { - /* set the output parameters to physical addresses */ - *lli_table_ptr = sep_shared_virt_to_bus(sep, in_lli_table_ptr); - *num_entries_ptr = num_entries_in_table; - *table_data_size_ptr = table_data_size; - - edbg("SEP Driver:output lli_table_in_ptr is %08lx\n", *lli_table_ptr); - } else { - /* update the info entry of the previous in table */ - info_entry_ptr->physical_address = sep_shared_virt_to_bus(sep, in_lli_table_ptr); - info_entry_ptr->block_size = ((num_entries_in_table) << 24) | (table_data_size); - } - - /* save the pointer to the info entry of the current tables */ - info_entry_ptr = in_lli_table_ptr + num_entries_in_table - 1; - } - - /* print input tables */ - sep_debug_print_lli_tables(sep, (struct sep_lli_entry_t *) - sep_shared_bus_to_virt(sep, *lli_table_ptr), *num_entries_ptr, *table_data_size_ptr); - - /* the array of the pages */ - kfree(lli_array_ptr); -end_function: - dbg("SEP Driver:<-------- sep_prepare_input_dma_table end\n"); - return 0; - -} - -/* - This function creates the input and output dma tables for - symmetric operations (AES/DES) according to the block size from LLI arays -*/ -static int sep_construct_dma_tables_from_lli(struct sep_device *sep, - struct sep_lli_entry_t *lli_in_array, - unsigned long sep_in_lli_entries, - struct sep_lli_entry_t *lli_out_array, - unsigned long sep_out_lli_entries, - unsigned long block_size, unsigned long *lli_table_in_ptr, unsigned long *lli_table_out_ptr, unsigned long *in_num_entries_ptr, unsigned long *out_num_entries_ptr, unsigned long *table_data_size_ptr) -{ - /* points to the area where next lli table can be allocated: keep void * - as there is pointer scaling to fix otherwise */ - void *lli_table_alloc_addr; - /* input lli table */ - struct sep_lli_entry_t *in_lli_table_ptr; - /* output lli table */ - struct sep_lli_entry_t *out_lli_table_ptr; - /* pointer to the info entry of the table - the last entry */ - struct sep_lli_entry_t *info_in_entry_ptr; - /* pointer to the info entry of the table - the last entry */ - struct sep_lli_entry_t *info_out_entry_ptr; - /* points to the first entry to be processed in the lli_in_array */ - unsigned long current_in_entry; - /* points to the first entry to be processed in the lli_out_array */ - unsigned long current_out_entry; - /* max size of the input table */ - unsigned long in_table_data_size; - /* max size of the output table */ - unsigned long out_table_data_size; - /* flag te signifies if this is the first tables build from the arrays */ - unsigned long first_table_flag; - /* the data size that should be in table */ - unsigned long table_data_size; - /* number of etnries in the input table */ - unsigned long num_entries_in_table; - /* number of etnries in the output table */ - unsigned long num_entries_out_table; - - dbg("SEP Driver:--------> sep_construct_dma_tables_from_lli start\n"); - - /* initiate to pint after the message area */ - lli_table_alloc_addr = sep->shared_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES; - - current_in_entry = 0; - current_out_entry = 0; - first_table_flag = 1; - info_in_entry_ptr = 0; - info_out_entry_ptr = 0; - - /* loop till all the entries in in array are not processed */ - while (current_in_entry < sep_in_lli_entries) { - /* set the new input and output tables */ - in_lli_table_ptr = (struct sep_lli_entry_t *) lli_table_alloc_addr; - - lli_table_alloc_addr += sizeof(struct sep_lli_entry_t) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP; - - /* set the first output tables */ - out_lli_table_ptr = (struct sep_lli_entry_t *) lli_table_alloc_addr; - - lli_table_alloc_addr += sizeof(struct sep_lli_entry_t) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP; - - /* calculate the maximum size of data for input table */ - in_table_data_size = sep_calculate_lli_table_max_size(&lli_in_array[current_in_entry], (sep_in_lli_entries - current_in_entry)); - - /* calculate the maximum size of data for output table */ - out_table_data_size = sep_calculate_lli_table_max_size(&lli_out_array[current_out_entry], (sep_out_lli_entries - current_out_entry)); - - edbg("SEP Driver:in_table_data_size is %lu\n", in_table_data_size); - edbg("SEP Driver:out_table_data_size is %lu\n", out_table_data_size); - - /* check where the data is smallest */ - table_data_size = in_table_data_size; - if (table_data_size > out_table_data_size) - table_data_size = out_table_data_size; - - /* now calculate the table size so that it will be module block size */ - table_data_size = (table_data_size / block_size) * block_size; - - dbg("SEP Driver:table_data_size is %lu\n", table_data_size); - - /* construct input lli table */ - sep_build_lli_table(&lli_in_array[current_in_entry], in_lli_table_ptr, ¤t_in_entry, &num_entries_in_table, table_data_size); - - /* construct output lli table */ - sep_build_lli_table(&lli_out_array[current_out_entry], out_lli_table_ptr, ¤t_out_entry, &num_entries_out_table, table_data_size); - - /* if info entry is null - this is the first table built */ - if (info_in_entry_ptr == 0) { - /* set the output parameters to physical addresses */ - *lli_table_in_ptr = sep_shared_virt_to_bus(sep, in_lli_table_ptr); - *in_num_entries_ptr = num_entries_in_table; - *lli_table_out_ptr = sep_shared_virt_to_bus(sep, out_lli_table_ptr); - *out_num_entries_ptr = num_entries_out_table; - *table_data_size_ptr = table_data_size; - - edbg("SEP Driver:output lli_table_in_ptr is %08lx\n", *lli_table_in_ptr); - edbg("SEP Driver:output lli_table_out_ptr is %08lx\n", *lli_table_out_ptr); - } else { - /* update the info entry of the previous in table */ - info_in_entry_ptr->physical_address = sep_shared_virt_to_bus(sep, in_lli_table_ptr); - info_in_entry_ptr->block_size = ((num_entries_in_table) << 24) | (table_data_size); - - /* update the info entry of the previous in table */ - info_out_entry_ptr->physical_address = sep_shared_virt_to_bus(sep, out_lli_table_ptr); - info_out_entry_ptr->block_size = ((num_entries_out_table) << 24) | (table_data_size); - } - - /* save the pointer to the info entry of the current tables */ - info_in_entry_ptr = in_lli_table_ptr + num_entries_in_table - 1; - info_out_entry_ptr = out_lli_table_ptr + num_entries_out_table - 1; - - edbg("SEP Driver:output num_entries_out_table is %lu\n", (unsigned long) num_entries_out_table); - edbg("SEP Driver:output info_in_entry_ptr is %lu\n", (unsigned long) info_in_entry_ptr); - edbg("SEP Driver:output info_out_entry_ptr is %lu\n", (unsigned long) info_out_entry_ptr); - } - - /* print input tables */ - sep_debug_print_lli_tables(sep, (struct sep_lli_entry_t *) - sep_shared_bus_to_virt(sep, *lli_table_in_ptr), *in_num_entries_ptr, *table_data_size_ptr); - /* print output tables */ - sep_debug_print_lli_tables(sep, (struct sep_lli_entry_t *) - sep_shared_bus_to_virt(sep, *lli_table_out_ptr), *out_num_entries_ptr, *table_data_size_ptr); - dbg("SEP Driver:<-------- sep_construct_dma_tables_from_lli end\n"); - return 0; -} - - -/* - This function builds input and output DMA tables for synhronic - symmetric operations (AES, DES). It also checks that each table - is of the modular block size -*/ -static int sep_prepare_input_output_dma_table(struct sep_device *sep, - unsigned long app_virt_in_addr, - unsigned long app_virt_out_addr, - unsigned long data_size, - unsigned long block_size, - unsigned long *lli_table_in_ptr, unsigned long *lli_table_out_ptr, unsigned long *in_num_entries_ptr, unsigned long *out_num_entries_ptr, unsigned long *table_data_size_ptr, bool isKernelVirtualAddress) -{ - /* array of pointers of page */ - struct sep_lli_entry_t *lli_in_array; - /* array of pointers of page */ - struct sep_lli_entry_t *lli_out_array; - int result = 0; - - dbg("SEP Driver:--------> sep_prepare_input_output_dma_table start\n"); - - /* initialize the pages pointers */ - sep->in_page_array = 0; - sep->out_page_array = 0; - - /* check if the pages are in Kernel Virtual Address layout */ - if (isKernelVirtualAddress == true) { - /* lock the pages of the kernel buffer and translate them to pages */ - result = sep_lock_kernel_pages(sep, app_virt_in_addr, data_size, &sep->in_num_pages, &lli_in_array, &sep->in_page_array); - if (result) { - edbg("SEP Driver: sep_lock_kernel_pages for input virtual buffer failed\n"); - goto end_function; - } - } else { - /* lock the pages of the user buffer and translate them to pages */ - result = sep_lock_user_pages(sep, app_virt_in_addr, data_size, &sep->in_num_pages, &lli_in_array, &sep->in_page_array); - if (result) { - edbg("SEP Driver: sep_lock_user_pages for input virtual buffer failed\n"); - goto end_function; - } - } - - if (isKernelVirtualAddress == true) { - result = sep_lock_kernel_pages(sep, app_virt_out_addr, data_size, &sep->out_num_pages, &lli_out_array, &sep->out_page_array); - if (result) { - edbg("SEP Driver: sep_lock_kernel_pages for output virtual buffer failed\n"); - goto end_function_with_error1; - } - } else { - result = sep_lock_user_pages(sep, app_virt_out_addr, data_size, &sep->out_num_pages, &lli_out_array, &sep->out_page_array); - if (result) { - edbg("SEP Driver: sep_lock_user_pages for output virtual buffer failed\n"); - goto end_function_with_error1; - } - } - edbg("sep->in_num_pages is %lu\n", sep->in_num_pages); - edbg("sep->out_num_pages is %lu\n", sep->out_num_pages); - edbg("SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP is %x\n", SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP); - - - /* call the fucntion that creates table from the lli arrays */ - result = sep_construct_dma_tables_from_lli(sep, lli_in_array, sep->in_num_pages, lli_out_array, sep->out_num_pages, block_size, lli_table_in_ptr, lli_table_out_ptr, in_num_entries_ptr, out_num_entries_ptr, table_data_size_ptr); - if (result) { - edbg("SEP Driver: sep_construct_dma_tables_from_lli failed\n"); - goto end_function_with_error2; - } - - /* fall through - free the lli entry arrays */ - dbg("in_num_entries_ptr is %08lx\n", *in_num_entries_ptr); - dbg("out_num_entries_ptr is %08lx\n", *out_num_entries_ptr); - dbg("table_data_size_ptr is %08lx\n", *table_data_size_ptr); -end_function_with_error2: - kfree(lli_out_array); -end_function_with_error1: - kfree(lli_in_array); -end_function: - dbg("SEP Driver:<-------- sep_prepare_input_output_dma_table end result = %d\n", (int) result); - return result; - -} - -/* - this function handles tha request for creation of the DMA table - for the synchronic symmetric operations (AES,DES) -*/ -static int sep_create_sync_dma_tables_handler(struct sep_device *sep, - unsigned long arg) -{ - int error; - /* command arguments */ - struct sep_driver_build_sync_table_t command_args; - - dbg("SEP Driver:--------> sep_create_sync_dma_tables_handler start\n"); - - error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_build_sync_table_t)); - if (error) { - error = -EFAULT; - goto end_function; - } - - edbg("app_in_address is %08lx\n", command_args.app_in_address); - edbg("app_out_address is %08lx\n", command_args.app_out_address); - edbg("data_size is %lu\n", command_args.data_in_size); - edbg("block_size is %lu\n", command_args.block_size); - - /* check if we need to build only input table or input/output */ - if (command_args.app_out_address) - /* prepare input and output tables */ - error = sep_prepare_input_output_dma_table(sep, - command_args.app_in_address, - command_args.app_out_address, - command_args.data_in_size, - command_args.block_size, - &command_args.in_table_address, - &command_args.out_table_address, &command_args.in_table_num_entries, &command_args.out_table_num_entries, &command_args.table_data_size, command_args.isKernelVirtualAddress); - else - /* prepare input tables */ - error = sep_prepare_input_dma_table(sep, - command_args.app_in_address, - command_args.data_in_size, command_args.block_size, &command_args.in_table_address, &command_args.in_table_num_entries, &command_args.table_data_size, command_args.isKernelVirtualAddress); - - if (error) - goto end_function; - /* copy to user */ - if (copy_to_user((void *) arg, (void *) &command_args, sizeof(struct sep_driver_build_sync_table_t))) - error = -EFAULT; -end_function: - dbg("SEP Driver:<-------- sep_create_sync_dma_tables_handler end\n"); - return error; -} - -/* - this function handles the request for freeing dma table for synhronic actions -*/ -static int sep_free_dma_table_data_handler(struct sep_device *sep) -{ - dbg("SEP Driver:--------> sep_free_dma_table_data_handler start\n"); - - /* free input pages array */ - sep_free_dma_pages(sep->in_page_array, sep->in_num_pages, 0); - - /* free output pages array if needed */ - if (sep->out_page_array) - sep_free_dma_pages(sep->out_page_array, sep->out_num_pages, 1); - - /* reset all the values */ - sep->in_page_array = 0; - sep->out_page_array = 0; - sep->in_num_pages = 0; - sep->out_num_pages = 0; - dbg("SEP Driver:<-------- sep_free_dma_table_data_handler end\n"); - return 0; -} - -/* - this function find a space for the new flow dma table -*/ -static int sep_find_free_flow_dma_table_space(struct sep_device *sep, - unsigned long **table_address_ptr) -{ - int error = 0; - /* pointer to the id field of the flow dma table */ - unsigned long *start_table_ptr; - /* Do not make start_addr unsigned long * unless fixing the offset - computations ! */ - void *flow_dma_area_start_addr; - unsigned long *flow_dma_area_end_addr; - /* maximum table size in words */ - unsigned long table_size_in_words; - - /* find the start address of the flow DMA table area */ - flow_dma_area_start_addr = sep->shared_addr + SEP_DRIVER_FLOW_DMA_TABLES_AREA_OFFSET_IN_BYTES; - - /* set end address of the flow table area */ - flow_dma_area_end_addr = flow_dma_area_start_addr + SEP_DRIVER_FLOW_DMA_TABLES_AREA_SIZE_IN_BYTES; - - /* set table size in words */ - table_size_in_words = SEP_DRIVER_MAX_FLOW_NUM_ENTRIES_IN_TABLE * (sizeof(struct sep_lli_entry_t) / sizeof(long)) + 2; - - /* set the pointer to the start address of DMA area */ - start_table_ptr = flow_dma_area_start_addr; - - /* find the space for the next table */ - while (((*start_table_ptr & 0x7FFFFFFF) != 0) && start_table_ptr < flow_dma_area_end_addr) - start_table_ptr += table_size_in_words; - - /* check if we reached the end of floa tables area */ - if (start_table_ptr >= flow_dma_area_end_addr) - error = -1; - else - *table_address_ptr = start_table_ptr; - - return error; -} - -/* - This function creates one DMA table for flow and returns its data, - and pointer to its info entry -*/ -static int sep_prepare_one_flow_dma_table(struct sep_device *sep, - unsigned long virt_buff_addr, - unsigned long virt_buff_size, - struct sep_lli_entry_t *table_data, - struct sep_lli_entry_t **info_entry_ptr, - struct sep_flow_context_t *flow_data_ptr, - bool isKernelVirtualAddress) -{ - int error; - /* the range in pages */ - unsigned long lli_array_size; - struct sep_lli_entry_t *lli_array; - struct sep_lli_entry_t *flow_dma_table_entry_ptr; - unsigned long *start_dma_table_ptr; - /* total table data counter */ - unsigned long dma_table_data_count; - /* pointer that will keep the pointer to the pages of the virtual buffer */ - struct page **page_array_ptr; - unsigned long entry_count; - - /* find the space for the new table */ - error = sep_find_free_flow_dma_table_space(sep, &start_dma_table_ptr); - if (error) - goto end_function; - - /* check if the pages are in Kernel Virtual Address layout */ - if (isKernelVirtualAddress == true) - /* lock kernel buffer in the memory */ - error = sep_lock_kernel_pages(sep, virt_buff_addr, virt_buff_size, &lli_array_size, &lli_array, &page_array_ptr); - else - /* lock user buffer in the memory */ - error = sep_lock_user_pages(sep, virt_buff_addr, virt_buff_size, &lli_array_size, &lli_array, &page_array_ptr); - - if (error) - goto end_function; - - /* set the pointer to page array at the beginning of table - this table is - now considered taken */ - *start_dma_table_ptr = lli_array_size; - - /* point to the place of the pages pointers of the table */ - start_dma_table_ptr++; - - /* set the pages pointer */ - *start_dma_table_ptr = (unsigned long) page_array_ptr; - - /* set the pointer to the first entry */ - flow_dma_table_entry_ptr = (struct sep_lli_entry_t *) (++start_dma_table_ptr); - - /* now create the entries for table */ - for (dma_table_data_count = entry_count = 0; entry_count < lli_array_size; entry_count++) { - flow_dma_table_entry_ptr->physical_address = lli_array[entry_count].physical_address; - - flow_dma_table_entry_ptr->block_size = lli_array[entry_count].block_size; - - /* set the total data of a table */ - dma_table_data_count += lli_array[entry_count].block_size; - - flow_dma_table_entry_ptr++; - } - - /* set the physical address */ - table_data->physical_address = virt_to_phys(start_dma_table_ptr); - - /* set the num_entries and total data size */ - table_data->block_size = ((lli_array_size + 1) << SEP_NUM_ENTRIES_OFFSET_IN_BITS) | (dma_table_data_count); - - /* set the info entry */ - flow_dma_table_entry_ptr->physical_address = 0xffffffff; - flow_dma_table_entry_ptr->block_size = 0; - - /* set the pointer to info entry */ - *info_entry_ptr = flow_dma_table_entry_ptr; - - /* the array of the lli entries */ - kfree(lli_array); -end_function: - return error; -} - - - -/* - This function creates a list of tables for flow and returns the data for - the first and last tables of the list -*/ -static int sep_prepare_flow_dma_tables(struct sep_device *sep, - unsigned long num_virtual_buffers, - unsigned long first_buff_addr, struct sep_flow_context_t *flow_data_ptr, struct sep_lli_entry_t *first_table_data_ptr, struct sep_lli_entry_t *last_table_data_ptr, bool isKernelVirtualAddress) -{ - int error; - unsigned long virt_buff_addr; - unsigned long virt_buff_size; - struct sep_lli_entry_t table_data; - struct sep_lli_entry_t *info_entry_ptr; - struct sep_lli_entry_t *prev_info_entry_ptr; - unsigned long i; - - /* init vars */ - error = 0; - prev_info_entry_ptr = 0; - - /* init the first table to default */ - table_data.physical_address = 0xffffffff; - first_table_data_ptr->physical_address = 0xffffffff; - table_data.block_size = 0; - - for (i = 0; i < num_virtual_buffers; i++) { - /* get the virtual buffer address */ - error = get_user(virt_buff_addr, &first_buff_addr); - if (error) - goto end_function; - - /* get the virtual buffer size */ - first_buff_addr++; - error = get_user(virt_buff_size, &first_buff_addr); - if (error) - goto end_function; - - /* advance the address to point to the next pair of address|size */ - first_buff_addr++; - - /* now prepare the one flow LLI table from the data */ - error = sep_prepare_one_flow_dma_table(sep, virt_buff_addr, virt_buff_size, &table_data, &info_entry_ptr, flow_data_ptr, isKernelVirtualAddress); - if (error) - goto end_function; - - if (i == 0) { - /* if this is the first table - save it to return to the user - application */ - *first_table_data_ptr = table_data; - - /* set the pointer to info entry */ - prev_info_entry_ptr = info_entry_ptr; - } else { - /* not first table - the previous table info entry should - be updated */ - prev_info_entry_ptr->block_size = (0x1 << SEP_INT_FLAG_OFFSET_IN_BITS) | (table_data.block_size); - - /* set the pointer to info entry */ - prev_info_entry_ptr = info_entry_ptr; - } - } - - /* set the last table data */ - *last_table_data_ptr = table_data; -end_function: - return error; -} - -/* - this function goes over all the flow tables connected to the given - table and deallocate them -*/ -static void sep_deallocated_flow_tables(struct sep_lli_entry_t *first_table_ptr) -{ - /* id pointer */ - unsigned long *table_ptr; - /* end address of the flow dma area */ - unsigned long num_entries; - unsigned long num_pages; - struct page **pages_ptr; - /* maximum table size in words */ - struct sep_lli_entry_t *info_entry_ptr; - - /* set the pointer to the first table */ - table_ptr = (unsigned long *) first_table_ptr->physical_address; - - /* set the num of entries */ - num_entries = (first_table_ptr->block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) - & SEP_NUM_ENTRIES_MASK; - - /* go over all the connected tables */ - while (*table_ptr != 0xffffffff) { - /* get number of pages */ - num_pages = *(table_ptr - 2); - - /* get the pointer to the pages */ - pages_ptr = (struct page **) (*(table_ptr - 1)); - - /* free the pages */ - sep_free_dma_pages(pages_ptr, num_pages, 1); - - /* goto to the info entry */ - info_entry_ptr = ((struct sep_lli_entry_t *) table_ptr) + (num_entries - 1); - - table_ptr = (unsigned long *) info_entry_ptr->physical_address; - num_entries = (info_entry_ptr->block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK; - } - - return; -} - -/** - * sep_find_flow_context - find a flow - * @sep: the SEP we are working with - * @flow_id: flow identifier - * - * Returns a pointer the matching flow, or NULL if the flow does not - * exist. - */ - -static struct sep_flow_context_t *sep_find_flow_context(struct sep_device *sep, - unsigned long flow_id) -{ - int count; - /* - * always search for flow with id default first - in case we - * already started working on the flow there can be no situation - * when 2 flows are with default flag - */ - for (count = 0; count < SEP_DRIVER_NUM_FLOWS; count++) { - if (sep->flows[count].flow_id == flow_id) - return &sep->flows[count]; - } - return NULL; -} - - -/* - this function handles the request to create the DMA tables for flow -*/ -static int sep_create_flow_dma_tables_handler(struct sep_device *sep, - unsigned long arg) -{ - int error = -ENOENT; - struct sep_driver_build_flow_table_t command_args; - /* first table - output */ - struct sep_lli_entry_t first_table_data; - /* dma table data */ - struct sep_lli_entry_t last_table_data; - /* pointer to the info entry of the previuos DMA table */ - struct sep_lli_entry_t *prev_info_entry_ptr; - /* pointer to the flow data strucutre */ - struct sep_flow_context_t *flow_context_ptr; - - dbg("SEP Driver:--------> sep_create_flow_dma_tables_handler start\n"); - - /* init variables */ - prev_info_entry_ptr = 0; - first_table_data.physical_address = 0xffffffff; - - /* find the free structure for flow data */ - error = -EINVAL; - flow_context_ptr = sep_find_flow_context(sep, SEP_FREE_FLOW_ID); - if (flow_context_ptr == NULL) - goto end_function; - - error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_build_flow_table_t)); - if (error) { - error = -EFAULT; - goto end_function; - } - - /* create flow tables */ - error = sep_prepare_flow_dma_tables(sep, command_args.num_virtual_buffers, command_args.virt_buff_data_addr, flow_context_ptr, &first_table_data, &last_table_data, command_args.isKernelVirtualAddress); - if (error) - goto end_function_with_error; - - /* check if flow is static */ - if (!command_args.flow_type) - /* point the info entry of the last to the info entry of the first */ - last_table_data = first_table_data; - - /* set output params */ - command_args.first_table_addr = first_table_data.physical_address; - command_args.first_table_num_entries = ((first_table_data.block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK); - command_args.first_table_data_size = (first_table_data.block_size & SEP_TABLE_DATA_SIZE_MASK); - - /* send the parameters to user application */ - error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_build_flow_table_t)); - if (error) { - error = -EFAULT; - goto end_function_with_error; - } - - /* all the flow created - update the flow entry with temp id */ - flow_context_ptr->flow_id = SEP_TEMP_FLOW_ID; - - /* set the processing tables data in the context */ - if (command_args.input_output_flag == SEP_DRIVER_IN_FLAG) - flow_context_ptr->input_tables_in_process = first_table_data; - else - flow_context_ptr->output_tables_in_process = first_table_data; - - goto end_function; - -end_function_with_error: - /* free the allocated tables */ - sep_deallocated_flow_tables(&first_table_data); -end_function: - dbg("SEP Driver:<-------- sep_create_flow_dma_tables_handler end\n"); - return error; -} - -/* - this function handles add tables to flow -*/ -static int sep_add_flow_tables_handler(struct sep_device *sep, unsigned long arg) -{ - int error; - unsigned long num_entries; - struct sep_driver_add_flow_table_t command_args; - struct sep_flow_context_t *flow_context_ptr; - /* first dma table data */ - struct sep_lli_entry_t first_table_data; - /* last dma table data */ - struct sep_lli_entry_t last_table_data; - /* pointer to the info entry of the current DMA table */ - struct sep_lli_entry_t *info_entry_ptr; - - dbg("SEP Driver:--------> sep_add_flow_tables_handler start\n"); - - /* get input parameters */ - error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_add_flow_table_t)); - if (error) { - error = -EFAULT; - goto end_function; - } - - /* find the flow structure for the flow id */ - flow_context_ptr = sep_find_flow_context(sep, command_args.flow_id); - if (flow_context_ptr == NULL) - goto end_function; - - /* prepare the flow dma tables */ - error = sep_prepare_flow_dma_tables(sep, command_args.num_virtual_buffers, command_args.virt_buff_data_addr, flow_context_ptr, &first_table_data, &last_table_data, command_args.isKernelVirtualAddress); - if (error) - goto end_function_with_error; - - /* now check if there is already an existing add table for this flow */ - if (command_args.inputOutputFlag == SEP_DRIVER_IN_FLAG) { - /* this buffer was for input buffers */ - if (flow_context_ptr->input_tables_flag) { - /* add table already exists - add the new tables to the end - of the previous */ - num_entries = (flow_context_ptr->last_input_table.block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK; - - info_entry_ptr = (struct sep_lli_entry_t *) - (flow_context_ptr->last_input_table.physical_address + (sizeof(struct sep_lli_entry_t) * (num_entries - 1))); - - /* connect to list of tables */ - *info_entry_ptr = first_table_data; - - /* set the first table data */ - first_table_data = flow_context_ptr->first_input_table; - } else { - /* set the input flag */ - flow_context_ptr->input_tables_flag = 1; - - /* set the first table data */ - flow_context_ptr->first_input_table = first_table_data; - } - /* set the last table data */ - flow_context_ptr->last_input_table = last_table_data; - } else { /* this is output tables */ - - /* this buffer was for input buffers */ - if (flow_context_ptr->output_tables_flag) { - /* add table already exists - add the new tables to - the end of the previous */ - num_entries = (flow_context_ptr->last_output_table.block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK; - - info_entry_ptr = (struct sep_lli_entry_t *) - (flow_context_ptr->last_output_table.physical_address + (sizeof(struct sep_lli_entry_t) * (num_entries - 1))); - - /* connect to list of tables */ - *info_entry_ptr = first_table_data; - - /* set the first table data */ - first_table_data = flow_context_ptr->first_output_table; - } else { - /* set the input flag */ - flow_context_ptr->output_tables_flag = 1; - - /* set the first table data */ - flow_context_ptr->first_output_table = first_table_data; - } - /* set the last table data */ - flow_context_ptr->last_output_table = last_table_data; - } - - /* set output params */ - command_args.first_table_addr = first_table_data.physical_address; - command_args.first_table_num_entries = ((first_table_data.block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK); - command_args.first_table_data_size = (first_table_data.block_size & SEP_TABLE_DATA_SIZE_MASK); - - /* send the parameters to user application */ - error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_add_flow_table_t)); - if (error) - error = -EFAULT; -end_function_with_error: - /* free the allocated tables */ - sep_deallocated_flow_tables(&first_table_data); -end_function: - dbg("SEP Driver:<-------- sep_add_flow_tables_handler end\n"); - return error; -} - -/* - this function add the flow add message to the specific flow -*/ -static int sep_add_flow_tables_message_handler(struct sep_device *sep, unsigned long arg) -{ - int error; - struct sep_driver_add_message_t command_args; - struct sep_flow_context_t *flow_context_ptr; - - dbg("SEP Driver:--------> sep_add_flow_tables_message_handler start\n"); - - error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_add_message_t)); - if (error) { - error = -EFAULT; - goto end_function; - } - - /* check input */ - if (command_args.message_size_in_bytes > SEP_MAX_ADD_MESSAGE_LENGTH_IN_BYTES) { - error = -ENOMEM; - goto end_function; - } - - /* find the flow context */ - flow_context_ptr = sep_find_flow_context(sep, command_args.flow_id); - if (flow_context_ptr == NULL) - goto end_function; - - /* copy the message into context */ - flow_context_ptr->message_size_in_bytes = command_args.message_size_in_bytes; - error = copy_from_user(flow_context_ptr->message, (void *) command_args.message_address, command_args.message_size_in_bytes); - if (error) - error = -EFAULT; -end_function: - dbg("SEP Driver:<-------- sep_add_flow_tables_message_handler end\n"); - return error; -} - - -/* - this function returns the bus and virtual addresses of the static pool -*/ -static int sep_get_static_pool_addr_handler(struct sep_device *sep, unsigned long arg) -{ - int error; - struct sep_driver_static_pool_addr_t command_args; - - dbg("SEP Driver:--------> sep_get_static_pool_addr_handler start\n"); - - /*prepare the output parameters in the struct */ - command_args.physical_static_address = sep->shared_bus + SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES; - command_args.virtual_static_address = (unsigned long)sep->shared_addr + SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES; - - edbg("SEP Driver:bus_static_address is %08lx, virtual_static_address %08lx\n", command_args.physical_static_address, command_args.virtual_static_address); - - /* send the parameters to user application */ - error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_static_pool_addr_t)); - if (error) - error = -EFAULT; - dbg("SEP Driver:<-------- sep_get_static_pool_addr_handler end\n"); - return error; -} - -/* - this address gets the offset of the physical address from the start - of the mapped area -*/ -static int sep_get_physical_mapped_offset_handler(struct sep_device *sep, unsigned long arg) -{ - int error; - struct sep_driver_get_mapped_offset_t command_args; - - dbg("SEP Driver:--------> sep_get_physical_mapped_offset_handler start\n"); - - error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_get_mapped_offset_t)); - if (error) { - error = -EFAULT; - goto end_function; - } - - if (command_args.physical_address < sep->shared_bus) { - error = -EINVAL; - goto end_function; - } - - /*prepare the output parameters in the struct */ - command_args.offset = command_args.physical_address - sep->shared_bus; - - edbg("SEP Driver:bus_address is %08lx, offset is %lu\n", command_args.physical_address, command_args.offset); - - /* send the parameters to user application */ - error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_get_mapped_offset_t)); - if (error) - error = -EFAULT; -end_function: - dbg("SEP Driver:<-------- sep_get_physical_mapped_offset_handler end\n"); - return error; -} - - -/* - ? -*/ -static int sep_start_handler(struct sep_device *sep) -{ - unsigned long reg_val; - unsigned long error = 0; - - dbg("SEP Driver:--------> sep_start_handler start\n"); - - /* wait in polling for message from SEP */ - do - reg_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR); - while (!reg_val); - - /* check the value */ - if (reg_val == 0x1) - /* fatal error - read error status from GPRO */ - error = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR0_REG_ADDR); - dbg("SEP Driver:<-------- sep_start_handler end\n"); - return error; -} - -/* - this function handles the request for SEP initialization -*/ -static int sep_init_handler(struct sep_device *sep, unsigned long arg) -{ - unsigned long message_word; - unsigned long *message_ptr; - struct sep_driver_init_t command_args; - unsigned long counter; - unsigned long error; - unsigned long reg_val; - - dbg("SEP Driver:--------> sep_init_handler start\n"); - error = 0; - - error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_init_t)); - if (error) { - error = -EFAULT; - goto end_function; - } - dbg("SEP Driver:--------> sep_init_handler - finished copy_from_user\n"); - - /* PATCH - configure the DMA to single -burst instead of multi-burst */ - /*sep_configure_dma_burst(); */ - - dbg("SEP Driver:--------> sep_init_handler - finished sep_configure_dma_burst \n"); - - message_ptr = (unsigned long *) command_args.message_addr; - - /* set the base address of the SRAM */ - sep_write_reg(sep, HW_SRAM_ADDR_REG_ADDR, HW_CC_SRAM_BASE_ADDRESS); - - for (counter = 0; counter < command_args.message_size_in_words; counter++, message_ptr++) { - get_user(message_word, message_ptr); - /* write data to SRAM */ - sep_write_reg(sep, HW_SRAM_DATA_REG_ADDR, message_word); - edbg("SEP Driver:message_word is %lu\n", message_word); - /* wait for write complete */ - sep_wait_sram_write(sep); - } - dbg("SEP Driver:--------> sep_init_handler - finished getting messages from user space\n"); - /* signal SEP */ - sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x1); - - do - reg_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR); - while (!(reg_val & 0xFFFFFFFD)); - - dbg("SEP Driver:--------> sep_init_handler - finished waiting for reg_val & 0xFFFFFFFD \n"); - - /* check the value */ - if (reg_val == 0x1) { - edbg("SEP Driver:init failed\n"); - - error = sep_read_reg(sep, 0x8060); - edbg("SEP Driver:sw monitor is %lu\n", error); - - /* fatal error - read erro status from GPRO */ - error = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR0_REG_ADDR); - edbg("SEP Driver:error is %lu\n", error); - } -end_function: - dbg("SEP Driver:<-------- sep_init_handler end\n"); - return error; - -} - -/* - this function handles the request cache and resident reallocation -*/ -static int sep_realloc_cache_resident_handler(struct sep_device *sep, - unsigned long arg) -{ - struct sep_driver_realloc_cache_resident_t command_args; - int error; - - /* copy cache and resident to the their intended locations */ - error = sep_load_firmware(sep); - if (error) - return error; - - command_args.new_base_addr = sep->shared_bus; - - /* find the new base address according to the lowest address between - cache, resident and shared area */ - if (sep->resident_bus < command_args.new_base_addr) - command_args.new_base_addr = sep->resident_bus; - if (sep->rar_bus < command_args.new_base_addr) - command_args.new_base_addr = sep->rar_bus; - - /* set the return parameters */ - command_args.new_cache_addr = sep->rar_bus; - command_args.new_resident_addr = sep->resident_bus; - - /* set the new shared area */ - command_args.new_shared_area_addr = sep->shared_bus; - - edbg("SEP Driver:command_args.new_shared_addr is %08llx\n", command_args.new_shared_area_addr); - edbg("SEP Driver:command_args.new_base_addr is %08llx\n", command_args.new_base_addr); - edbg("SEP Driver:command_args.new_resident_addr is %08llx\n", command_args.new_resident_addr); - edbg("SEP Driver:command_args.new_rar_addr is %08llx\n", command_args.new_cache_addr); - - /* return to user */ - if (copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_realloc_cache_resident_t))) - return -EFAULT; - return 0; -} - -/** - * sep_get_time_handler - time request from user space - * @sep: sep we are to set the time for - * @arg: pointer to user space arg buffer - * - * This function reports back the time and the address in the SEP - * shared buffer at which it has been placed. (Do we really need this!!!) - */ - -static int sep_get_time_handler(struct sep_device *sep, unsigned long arg) -{ - struct sep_driver_get_time_t command_args; - - mutex_lock(&sep_mutex); - command_args.time_value = sep_set_time(sep); - command_args.time_physical_address = (unsigned long)sep_time_address(sep); - mutex_unlock(&sep_mutex); - if (copy_to_user((void __user *)arg, - &command_args, sizeof(struct sep_driver_get_time_t))) - return -EFAULT; - return 0; - -} - -/* - This API handles the end transaction request -*/ -static int sep_end_transaction_handler(struct sep_device *sep, unsigned long arg) -{ - dbg("SEP Driver:--------> sep_end_transaction_handler start\n"); - -#if 0 /*!SEP_DRIVER_POLLING_MODE */ - /* close IMR */ - sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, 0x7FFF); - - /* release IRQ line */ - free_irq(SEP_DIRVER_IRQ_NUM, sep); - - /* lock the sep mutex */ - mutex_unlock(&sep_mutex); -#endif - - dbg("SEP Driver:<-------- sep_end_transaction_handler end\n"); - - return 0; -} - - -/** - * sep_set_flow_id_handler - handle flow setting - * @sep: the SEP we are configuring - * @flow_id: the flow we are setting - * - * This function handler the set flow id command - */ -static int sep_set_flow_id_handler(struct sep_device *sep, - unsigned long flow_id) -{ - int error = 0; - struct sep_flow_context_t *flow_data_ptr; - - /* find the flow data structure that was just used for creating new flow - - its id should be default */ - - mutex_lock(&sep_mutex); - flow_data_ptr = sep_find_flow_context(sep, SEP_TEMP_FLOW_ID); - if (flow_data_ptr) - flow_data_ptr->flow_id = flow_id; /* set flow id */ - else - error = -EINVAL; - mutex_unlock(&sep_mutex); - return error; -} - -static long sep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - int error = 0; - struct sep_device *sep = filp->private_data; - - dbg("------------>SEP Driver: ioctl start\n"); - - edbg("SEP Driver: cmd is %x\n", cmd); - - switch (cmd) { - case SEP_IOCSENDSEPCOMMAND: - /* send command to SEP */ - sep_send_command_handler(sep); - edbg("SEP Driver: after sep_send_command_handler\n"); - break; - case SEP_IOCSENDSEPRPLYCOMMAND: - /* send reply command to SEP */ - sep_send_reply_command_handler(sep); - break; - case SEP_IOCALLOCDATAPOLL: - /* allocate data pool */ - error = sep_allocate_data_pool_memory_handler(sep, arg); - break; - case SEP_IOCWRITEDATAPOLL: - /* write data into memory pool */ - error = sep_write_into_data_pool_handler(sep, arg); - break; - case SEP_IOCREADDATAPOLL: - /* read data from data pool into application memory */ - error = sep_read_from_data_pool_handler(sep, arg); - break; - case SEP_IOCCREATESYMDMATABLE: - /* create dma table for synhronic operation */ - error = sep_create_sync_dma_tables_handler(sep, arg); - break; - case SEP_IOCCREATEFLOWDMATABLE: - /* create flow dma tables */ - error = sep_create_flow_dma_tables_handler(sep, arg); - break; - case SEP_IOCFREEDMATABLEDATA: - /* free the pages */ - error = sep_free_dma_table_data_handler(sep); - break; - case SEP_IOCSETFLOWID: - /* set flow id */ - error = sep_set_flow_id_handler(sep, (unsigned long)arg); - break; - case SEP_IOCADDFLOWTABLE: - /* add tables to the dynamic flow */ - error = sep_add_flow_tables_handler(sep, arg); - break; - case SEP_IOCADDFLOWMESSAGE: - /* add message of add tables to flow */ - error = sep_add_flow_tables_message_handler(sep, arg); - break; - case SEP_IOCSEPSTART: - /* start command to sep */ - error = sep_start_handler(sep); - break; - case SEP_IOCSEPINIT: - /* init command to sep */ - error = sep_init_handler(sep, arg); - break; - case SEP_IOCGETSTATICPOOLADDR: - /* get the physical and virtual addresses of the static pool */ - error = sep_get_static_pool_addr_handler(sep, arg); - break; - case SEP_IOCENDTRANSACTION: - error = sep_end_transaction_handler(sep, arg); - break; - case SEP_IOCREALLOCCACHERES: - error = sep_realloc_cache_resident_handler(sep, arg); - break; - case SEP_IOCGETMAPPEDADDROFFSET: - error = sep_get_physical_mapped_offset_handler(sep, arg); - break; - case SEP_IOCGETIME: - error = sep_get_time_handler(sep, arg); - break; - default: - error = -ENOTTY; - break; - } - dbg("SEP Driver:<-------- ioctl end\n"); - return error; -} - - - -#if !SEP_DRIVER_POLLING_MODE - -/* handler for flow done interrupt */ - -static void sep_flow_done_handler(struct work_struct *work) -{ - struct sep_flow_context_t *flow_data_ptr; - - /* obtain the mutex */ - mutex_lock(&sep_mutex); - - /* get the pointer to context */ - flow_data_ptr = (struct sep_flow_context_t *) work; - - /* free all the current input tables in sep */ - sep_deallocated_flow_tables(&flow_data_ptr->input_tables_in_process); - - /* free all the current tables output tables in SEP (if needed) */ - if (flow_data_ptr->output_tables_in_process.physical_address != 0xffffffff) - sep_deallocated_flow_tables(&flow_data_ptr->output_tables_in_process); - - /* check if we have additional tables to be sent to SEP only input - flag may be checked */ - if (flow_data_ptr->input_tables_flag) { - /* copy the message to the shared RAM and signal SEP */ - memcpy((void *) flow_data_ptr->message, (void *) sep->shared_addr, flow_data_ptr->message_size_in_bytes); - - sep_write_reg(sep, HW_HOST_HOST_SEP_GPR2_REG_ADDR, 0x2); - } - mutex_unlock(&sep_mutex); -} -/* - interrupt handler function -*/ -static irqreturn_t sep_inthandler(int irq, void *dev_id) -{ - irqreturn_t int_error; - unsigned long reg_val; - unsigned long flow_id; - struct sep_flow_context_t *flow_context_ptr; - struct sep_device *sep = dev_id; - - int_error = IRQ_HANDLED; - - /* read the IRR register to check if this is SEP interrupt */ - reg_val = sep_read_reg(sep, HW_HOST_IRR_REG_ADDR); - edbg("SEP Interrupt - reg is %08lx\n", reg_val); - - /* check if this is the flow interrupt */ - if (0 /*reg_val & (0x1 << 11) */ ) { - /* read GPRO to find out the which flow is done */ - flow_id = sep_read_reg(sep, HW_HOST_IRR_REG_ADDR); - - /* find the contex of the flow */ - flow_context_ptr = sep_find_flow_context(sep, flow_id >> 28); - if (flow_context_ptr == NULL) - goto end_function_with_error; - - /* queue the work */ - INIT_WORK(&flow_context_ptr->flow_wq, sep_flow_done_handler); - queue_work(sep->flow_wq, &flow_context_ptr->flow_wq); - - } else { - /* check if this is reply interrupt from SEP */ - if (reg_val & (0x1 << 13)) { - /* update the counter of reply messages */ - sep->reply_ct++; - /* wake up the waiting process */ - wake_up(&sep_event); - } else { - int_error = IRQ_NONE; - goto end_function; - } - } -end_function_with_error: - /* clear the interrupt */ - sep_write_reg(sep, HW_HOST_ICR_REG_ADDR, reg_val); -end_function: - return int_error; -} - -#endif - - - -#if 0 - -static void sep_wait_busy(struct sep_device *sep) -{ - u32 reg; - - do { - reg = sep_read_reg(sep, HW_HOST_SEP_BUSY_REG_ADDR); - } while (reg); -} - -/* - PATCH for configuring the DMA to single burst instead of multi-burst -*/ -static void sep_configure_dma_burst(struct sep_device *sep) -{ -#define HW_AHB_RD_WR_BURSTS_REG_ADDR 0x0E10UL - - dbg("SEP Driver:<-------- sep_configure_dma_burst start \n"); - - /* request access to registers from SEP */ - sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x2); - - dbg("SEP Driver:<-------- sep_configure_dma_burst finished request access to registers from SEP (write reg) \n"); - - sep_wait_busy(sep); - - dbg("SEP Driver:<-------- sep_configure_dma_burst finished request access to registers from SEP (while(revVal) wait loop) \n"); - - /* set the DMA burst register to single burst */ - sep_write_reg(sep, HW_AHB_RD_WR_BURSTS_REG_ADDR, 0x0UL); - - /* release the sep busy */ - sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x0UL); - sep_wait_busy(sep); - - dbg("SEP Driver:<-------- sep_configure_dma_burst done \n"); - -} - -#endif - -/* - Function that is activated on the successful probe of the SEP device -*/ -static int __devinit sep_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - int error = 0; - struct sep_device *sep; - int counter; - int size; /* size of memory for allocation */ - - edbg("Sep pci probe starting\n"); - if (sep_dev != NULL) { - dev_warn(&pdev->dev, "only one SEP supported.\n"); - return -EBUSY; - } - - /* enable the device */ - error = pci_enable_device(pdev); - if (error) { - edbg("error enabling pci device\n"); - goto end_function; - } - - /* set the pci dev pointer */ - sep_dev = &sep_instance; - sep = &sep_instance; - - edbg("sep->shared_addr = %p\n", sep->shared_addr); - /* transaction counter that coordinates the transactions between SEP - and HOST */ - sep->send_ct = 0; - /* counter for the messages from sep */ - sep->reply_ct = 0; - /* counter for the number of bytes allocated in the pool - for the current transaction */ - sep->data_pool_bytes_allocated = 0; - - /* calculate the total size for allocation */ - size = SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES + - SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_SIZE_IN_BYTES + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES + SEP_DRIVER_FLOW_DMA_TABLES_AREA_SIZE_IN_BYTES + SEP_DRIVER_STATIC_AREA_SIZE_IN_BYTES + SEP_DRIVER_SYSTEM_DATA_MEMORY_SIZE_IN_BYTES; - - /* allocate the shared area */ - if (sep_map_and_alloc_shared_area(sep, size)) { - error = -ENOMEM; - /* allocation failed */ - goto end_function_error; - } - /* now set the memory regions */ -#if (SEP_DRIVER_RECONFIG_MESSAGE_AREA == 1) - /* Note: this test section will need moving before it could ever - work as the registers are not yet mapped ! */ - /* send the new SHARED MESSAGE AREA to the SEP */ - sep_write_reg(sep, HW_HOST_HOST_SEP_GPR1_REG_ADDR, sep->shared_bus); - - /* poll for SEP response */ - retval = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR1_REG_ADDR); - while (retval != 0xffffffff && retval != sep->shared_bus) - retval = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR1_REG_ADDR); - - /* check the return value (register) */ - if (retval != sep->shared_bus) { - error = -ENOMEM; - goto end_function_deallocate_sep_shared_area; - } -#endif - /* init the flow contextes */ - for (counter = 0; counter < SEP_DRIVER_NUM_FLOWS; counter++) - sep->flows[counter].flow_id = SEP_FREE_FLOW_ID; - - sep->flow_wq = create_singlethread_workqueue("sepflowwq"); - if (sep->flow_wq == NULL) { - error = -ENOMEM; - edbg("sep_driver:flow queue creation failed\n"); - goto end_function_deallocate_sep_shared_area; - } - edbg("SEP Driver: create flow workqueue \n"); - sep->pdev = pci_dev_get(pdev); - - sep->reg_addr = pci_ioremap_bar(pdev, 0); - if (!sep->reg_addr) { - edbg("sep: ioremap of registers failed.\n"); - goto end_function_deallocate_sep_shared_area; - } - edbg("SEP Driver:reg_addr is %p\n", sep->reg_addr); - - /* load the rom code */ - sep_load_rom_code(sep); - - /* set up system base address and shared memory location */ - sep->rar_addr = dma_alloc_coherent(&sep->pdev->dev, - 2 * SEP_RAR_IO_MEM_REGION_SIZE, - &sep->rar_bus, GFP_KERNEL); - - if (!sep->rar_addr) { - edbg("SEP Driver:can't allocate rar\n"); - goto end_function_uniomap; - } - - - edbg("SEP Driver:rar_bus is %08llx\n", (unsigned long long)sep->rar_bus); - edbg("SEP Driver:rar_virtual is %p\n", sep->rar_addr); - -#if !SEP_DRIVER_POLLING_MODE - - edbg("SEP Driver: about to write IMR and ICR REG_ADDR\n"); - - /* clear ICR register */ - sep_write_reg(sep, HW_HOST_ICR_REG_ADDR, 0xFFFFFFFF); - - /* set the IMR register - open only GPR 2 */ - sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, (~(0x1 << 13))); - - edbg("SEP Driver: about to call request_irq\n"); - /* get the interrupt line */ - error = request_irq(pdev->irq, sep_inthandler, IRQF_SHARED, "sep_driver", sep); - if (error) - goto end_function_free_res; - return 0; - edbg("SEP Driver: about to write IMR REG_ADDR"); - - /* set the IMR register - open only GPR 2 */ - sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, (~(0x1 << 13))); - -end_function_free_res: - dma_free_coherent(&sep->pdev->dev, 2 * SEP_RAR_IO_MEM_REGION_SIZE, - sep->rar_addr, sep->rar_bus); -#endif /* SEP_DRIVER_POLLING_MODE */ -end_function_uniomap: - iounmap(sep->reg_addr); -end_function_deallocate_sep_shared_area: - /* de-allocate shared area */ - sep_unmap_and_free_shared_area(sep, size); -end_function_error: - sep_dev = NULL; -end_function: - return error; -} - -static const struct pci_device_id sep_pci_id_tbl[] = { - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080c)}, - {0} -}; - -MODULE_DEVICE_TABLE(pci, sep_pci_id_tbl); - -/* field for registering driver to PCI device */ -static struct pci_driver sep_pci_driver = { - .name = "sep_sec_driver", - .id_table = sep_pci_id_tbl, - .probe = sep_probe - /* FIXME: remove handler */ -}; - -/* major and minor device numbers */ -static dev_t sep_devno; - -/* the files operations structure of the driver */ -static struct file_operations sep_file_operations = { - .owner = THIS_MODULE, - .unlocked_ioctl = sep_ioctl, - .poll = sep_poll, - .open = sep_open, - .release = sep_release, - .mmap = sep_mmap, -}; - - -/* cdev struct of the driver */ -static struct cdev sep_cdev; - -/* - this function registers the driver to the file system -*/ -static int sep_register_driver_to_fs(void) -{ - int ret_val = alloc_chrdev_region(&sep_devno, 0, 1, "sep_sec_driver"); - if (ret_val) { - edbg("sep: major number allocation failed, retval is %d\n", - ret_val); - return ret_val; - } - /* init cdev */ - cdev_init(&sep_cdev, &sep_file_operations); - sep_cdev.owner = THIS_MODULE; - - /* register the driver with the kernel */ - ret_val = cdev_add(&sep_cdev, sep_devno, 1); - if (ret_val) { - edbg("sep_driver:cdev_add failed, retval is %d\n", ret_val); - /* unregister dev numbers */ - unregister_chrdev_region(sep_devno, 1); - } - return ret_val; -} - - -/*-------------------------------------------------------------- - init function -----------------------------------------------------------------*/ -static int __init sep_init(void) -{ - int ret_val = 0; - dbg("SEP Driver:-------->Init start\n"); - /* FIXME: Probe can occur before we are ready to survive a probe */ - ret_val = pci_register_driver(&sep_pci_driver); - if (ret_val) { - edbg("sep_driver:sep_driver_to_device failed, ret_val is %d\n", ret_val); - goto end_function_unregister_from_fs; - } - /* register driver to fs */ - ret_val = sep_register_driver_to_fs(); - if (ret_val) - goto end_function_unregister_pci; - goto end_function; -end_function_unregister_pci: - pci_unregister_driver(&sep_pci_driver); -end_function_unregister_from_fs: - /* unregister from fs */ - cdev_del(&sep_cdev); - /* unregister dev numbers */ - unregister_chrdev_region(sep_devno, 1); -end_function: - dbg("SEP Driver:<-------- Init end\n"); - return ret_val; -} - - -/*------------------------------------------------------------- - exit function ---------------------------------------------------------------*/ -static void __exit sep_exit(void) -{ - int size; - - dbg("SEP Driver:--------> Exit start\n"); - - /* unregister from fs */ - cdev_del(&sep_cdev); - /* unregister dev numbers */ - unregister_chrdev_region(sep_devno, 1); - /* calculate the total size for de-allocation */ - size = SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES + - SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_SIZE_IN_BYTES + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES + SEP_DRIVER_FLOW_DMA_TABLES_AREA_SIZE_IN_BYTES + SEP_DRIVER_STATIC_AREA_SIZE_IN_BYTES + SEP_DRIVER_SYSTEM_DATA_MEMORY_SIZE_IN_BYTES; - /* FIXME: We need to do this in the unload for the device */ - /* free shared area */ - if (sep_dev) { - sep_unmap_and_free_shared_area(sep_dev, size); - edbg("SEP Driver: free pages SEP SHARED AREA \n"); - iounmap((void *) sep_dev->reg_addr); - edbg("SEP Driver: iounmap \n"); - } - edbg("SEP Driver: release_mem_region \n"); - dbg("SEP Driver:<-------- Exit end\n"); -} - - -module_init(sep_init); -module_exit(sep_exit); - -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/sep/sep_driver_api.h b/drivers/staging/sep/sep_driver_api.h deleted file mode 100644 index 7ef16da..0000000 --- a/drivers/staging/sep/sep_driver_api.h +++ /dev/null @@ -1,425 +0,0 @@ -/* - * - * sep_driver_api.h - Security Processor Driver api definitions - * - * Copyright(c) 2009 Intel Corporation. All rights reserved. - * Copyright(c) 2009 Discretix. 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 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. - * - * CONTACTS: - * - * Mark Allyn mark.a.allyn@intel.com - * - * CHANGES: - * - * 2009.06.26 Initial publish - * - */ - -#ifndef __SEP_DRIVER_API_H__ -#define __SEP_DRIVER_API_H__ - - - -/*---------------------------------------------------------------- - IOCTL command defines - -----------------------------------------------------------------*/ - -/* magic number 1 of the sep IOCTL command */ -#define SEP_IOC_MAGIC_NUMBER 's' - -/* sends interrupt to sep that message is ready */ -#define SEP_IOCSENDSEPCOMMAND _IO(SEP_IOC_MAGIC_NUMBER , 0) - -/* sends interrupt to sep that message is ready */ -#define SEP_IOCSENDSEPRPLYCOMMAND _IO(SEP_IOC_MAGIC_NUMBER , 1) - -/* allocate memory in data pool */ -#define SEP_IOCALLOCDATAPOLL _IO(SEP_IOC_MAGIC_NUMBER , 2) - -/* write to pre-allocated memory in data pool */ -#define SEP_IOCWRITEDATAPOLL _IO(SEP_IOC_MAGIC_NUMBER , 3) - -/* read from pre-allocated memory in data pool */ -#define SEP_IOCREADDATAPOLL _IO(SEP_IOC_MAGIC_NUMBER , 4) - -/* create sym dma lli tables */ -#define SEP_IOCCREATESYMDMATABLE _IO(SEP_IOC_MAGIC_NUMBER , 5) - -/* create flow dma lli tables */ -#define SEP_IOCCREATEFLOWDMATABLE _IO(SEP_IOC_MAGIC_NUMBER , 6) - -/* free dynamic data aalocated during table creation */ -#define SEP_IOCFREEDMATABLEDATA _IO(SEP_IOC_MAGIC_NUMBER , 7) - -/* get the static pool area addresses (physical and virtual) */ -#define SEP_IOCGETSTATICPOOLADDR _IO(SEP_IOC_MAGIC_NUMBER , 8) - -/* set flow id command */ -#define SEP_IOCSETFLOWID _IO(SEP_IOC_MAGIC_NUMBER , 9) - -/* add tables to the dynamic flow */ -#define SEP_IOCADDFLOWTABLE _IO(SEP_IOC_MAGIC_NUMBER , 10) - -/* add flow add tables message */ -#define SEP_IOCADDFLOWMESSAGE _IO(SEP_IOC_MAGIC_NUMBER , 11) - -/* start sep command */ -#define SEP_IOCSEPSTART _IO(SEP_IOC_MAGIC_NUMBER , 12) - -/* init sep command */ -#define SEP_IOCSEPINIT _IO(SEP_IOC_MAGIC_NUMBER , 13) - -/* end transaction command */ -#define SEP_IOCENDTRANSACTION _IO(SEP_IOC_MAGIC_NUMBER , 15) - -/* reallocate cache and resident */ -#define SEP_IOCREALLOCCACHERES _IO(SEP_IOC_MAGIC_NUMBER , 16) - -/* get the offset of the address starting from the beginnnig of the map area */ -#define SEP_IOCGETMAPPEDADDROFFSET _IO(SEP_IOC_MAGIC_NUMBER , 17) - -/* get time address and value */ -#define SEP_IOCGETIME _IO(SEP_IOC_MAGIC_NUMBER , 19) - -/*------------------------------------------- - TYPEDEFS -----------------------------------------------*/ - -/* - init command struct -*/ -struct sep_driver_init_t { - /* start of the 1G of the host memory address that SEP can access */ - unsigned long message_addr; - - /* start address of resident */ - unsigned long message_size_in_words; - -}; - - -/* - realloc cache resident command -*/ -struct sep_driver_realloc_cache_resident_t { - /* new cache address */ - u64 new_cache_addr; - /* new resident address */ - u64 new_resident_addr; - /* new resident address */ - u64 new_shared_area_addr; - /* new base address */ - u64 new_base_addr; -}; - -struct sep_driver_alloc_t { - /* virtual address of allocated space */ - unsigned long offset; - - /* physical address of allocated space */ - unsigned long phys_address; - - /* number of bytes to allocate */ - unsigned long num_bytes; -}; - -/* - */ -struct sep_driver_write_t { - /* application space address */ - unsigned long app_address; - - /* address of the data pool */ - unsigned long datapool_address; - - /* number of bytes to write */ - unsigned long num_bytes; -}; - -/* - */ -struct sep_driver_read_t { - /* application space address */ - unsigned long app_address; - - /* address of the data pool */ - unsigned long datapool_address; - - /* number of bytes to read */ - unsigned long num_bytes; -}; - -/* -*/ -struct sep_driver_build_sync_table_t { - /* address value of the data in */ - unsigned long app_in_address; - - /* size of data in */ - unsigned long data_in_size; - - /* address of the data out */ - unsigned long app_out_address; - - /* the size of the block of the operation - if needed, - every table will be modulo this parameter */ - unsigned long block_size; - - /* the physical address of the first input DMA table */ - unsigned long in_table_address; - - /* number of entries in the first input DMA table */ - unsigned long in_table_num_entries; - - /* the physical address of the first output DMA table */ - unsigned long out_table_address; - - /* number of entries in the first output DMA table */ - unsigned long out_table_num_entries; - - /* data in the first input table */ - unsigned long table_data_size; - - /* distinct user/kernel layout */ - bool isKernelVirtualAddress; - -}; - -/* -*/ -struct sep_driver_build_flow_table_t { - /* flow type */ - unsigned long flow_type; - - /* flag for input output */ - unsigned long input_output_flag; - - /* address value of the data in */ - unsigned long virt_buff_data_addr; - - /* size of data in */ - unsigned long num_virtual_buffers; - - /* the physical address of the first input DMA table */ - unsigned long first_table_addr; - - /* number of entries in the first input DMA table */ - unsigned long first_table_num_entries; - - /* data in the first input table */ - unsigned long first_table_data_size; - - /* distinct user/kernel layout */ - bool isKernelVirtualAddress; -}; - - -struct sep_driver_add_flow_table_t { - /* flow id */ - unsigned long flow_id; - - /* flag for input output */ - unsigned long inputOutputFlag; - - /* address value of the data in */ - unsigned long virt_buff_data_addr; - - /* size of data in */ - unsigned long num_virtual_buffers; - - /* address of the first table */ - unsigned long first_table_addr; - - /* number of entries in the first table */ - unsigned long first_table_num_entries; - - /* data size of the first table */ - unsigned long first_table_data_size; - - /* distinct user/kernel layout */ - bool isKernelVirtualAddress; - -}; - -/* - command struct for set flow id -*/ -struct sep_driver_set_flow_id_t { - /* flow id to set */ - unsigned long flow_id; -}; - - -/* command struct for add tables message */ -struct sep_driver_add_message_t { - /* flow id to set */ - unsigned long flow_id; - - /* message size in bytes */ - unsigned long message_size_in_bytes; - - /* address of the message */ - unsigned long message_address; -}; - -/* command struct for static pool addresses */ -struct sep_driver_static_pool_addr_t { - /* physical address of the static pool */ - unsigned long physical_static_address; - - /* virtual address of the static pool */ - unsigned long virtual_static_address; -}; - -/* command struct for getiing offset of the physical address from - the start of the mapped area */ -struct sep_driver_get_mapped_offset_t { - /* physical address of the static pool */ - unsigned long physical_address; - - /* virtual address of the static pool */ - unsigned long offset; -}; - -/* command struct for getting time value and address */ -struct sep_driver_get_time_t { - /* physical address of stored time */ - unsigned long time_physical_address; - - /* value of the stored time */ - unsigned long time_value; -}; - - -/* - structure that represent one entry in the DMA LLI table -*/ -struct sep_lli_entry_t { - /* physical address */ - unsigned long physical_address; - - /* block size */ - unsigned long block_size; -}; - -/* - structure that reperesents data needed for lli table construction -*/ -struct sep_lli_prepare_table_data_t { - /* pointer to the memory where the first lli entry to be built */ - struct sep_lli_entry_t *lli_entry_ptr; - - /* pointer to the array of lli entries from which the table is to be built */ - struct sep_lli_entry_t *lli_array_ptr; - - /* number of elements in lli array */ - int lli_array_size; - - /* number of entries in the created table */ - int num_table_entries; - - /* number of array entries processed during table creation */ - int num_array_entries_processed; - - /* the totatl data size in the created table */ - int lli_table_total_data_size; -}; - -/* - structure that represent tone table - it is not used in code, jkust - to show what table looks like -*/ -struct sep_lli_table_t { - /* number of pages mapped in this tables. If 0 - means that the table - is not defined (used as a valid flag) */ - unsigned long num_pages; - /* - pointer to array of page pointers that represent the mapping of the - virtual buffer defined by the table to the physical memory. If this - pointer is NULL, it means that the table is not defined - (used as a valid flag) - */ - struct page **table_page_array_ptr; - - /* maximum flow entries in table */ - struct sep_lli_entry_t lli_entries[SEP_DRIVER_MAX_FLOW_NUM_ENTRIES_IN_TABLE]; -}; - - -/* - structure for keeping the mapping of the virtual buffer into physical pages -*/ -struct sep_flow_buffer_data { - /* pointer to the array of page structs pointers to the pages of the - virtual buffer */ - struct page **page_array_ptr; - - /* number of pages taken by the virtual buffer */ - unsigned long num_pages; - - /* this flag signals if this page_array is the last one among many that were - sent in one setting to SEP */ - unsigned long last_page_array_flag; -}; - -/* - struct that keeps all the data for one flow -*/ -struct sep_flow_context_t { - /* - work struct for handling the flow done interrupt in the workqueue - this structure must be in the first place, since it will be used - forcasting to the containing flow context - */ - struct work_struct flow_wq; - - /* flow id */ - unsigned long flow_id; - - /* additional input tables exists */ - unsigned long input_tables_flag; - - /* additional output tables exists */ - unsigned long output_tables_flag; - - /* data of the first input file */ - struct sep_lli_entry_t first_input_table; - - /* data of the first output table */ - struct sep_lli_entry_t first_output_table; - - /* last input table data */ - struct sep_lli_entry_t last_input_table; - - /* last output table data */ - struct sep_lli_entry_t last_output_table; - - /* first list of table */ - struct sep_lli_entry_t input_tables_in_process; - - /* output table in process (in sep) */ - struct sep_lli_entry_t output_tables_in_process; - - /* size of messages in bytes */ - unsigned long message_size_in_bytes; - - /* message */ - unsigned char message[SEP_MAX_ADD_MESSAGE_LENGTH_IN_BYTES]; -}; - - -#endif diff --git a/drivers/staging/sep/sep_driver_config.h b/drivers/staging/sep/sep_driver_config.h deleted file mode 100644 index 6008fe5..0000000 --- a/drivers/staging/sep/sep_driver_config.h +++ /dev/null @@ -1,225 +0,0 @@ -/* - * - * sep_driver_config.h - Security Processor Driver configuration - * - * Copyright(c) 2009 Intel Corporation. All rights reserved. - * Copyright(c) 2009 Discretix. 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 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. - * - * CONTACTS: - * - * Mark Allyn mark.a.allyn@intel.com - * - * CHANGES: - * - * 2009.06.26 Initial publish - * - */ - -#ifndef __SEP_DRIVER_CONFIG_H__ -#define __SEP_DRIVER_CONFIG_H__ - - -/*-------------------------------------- - DRIVER CONFIGURATION FLAGS - -------------------------------------*/ - -/* if flag is on , then the driver is running in polling and - not interrupt mode */ -#define SEP_DRIVER_POLLING_MODE 1 - -/* flag which defines if the shared area address should be - reconfiged (send to SEP anew) during init of the driver */ -#define SEP_DRIVER_RECONFIG_MESSAGE_AREA 0 - -/* the mode for running on the ARM1172 Evaluation platform (flag is 1) */ -#define SEP_DRIVER_ARM_DEBUG_MODE 0 - -/*------------------------------------------- - INTERNAL DATA CONFIGURATION - -------------------------------------------*/ - -/* flag for the input array */ -#define SEP_DRIVER_IN_FLAG 0 - -/* flag for output array */ -#define SEP_DRIVER_OUT_FLAG 1 - -/* maximum number of entries in one LLI tables */ -#define SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP 8 - - -/*-------------------------------------------------------- - SHARED AREA memory total size is 36K - it is divided is following: - - SHARED_MESSAGE_AREA 8K } - } - STATIC_POOL_AREA 4K } MAPPED AREA ( 24 K) - } - DATA_POOL_AREA 12K } - - SYNCHRONIC_DMA_TABLES_AREA 5K - - FLOW_DMA_TABLES_AREA 4K - - SYSTEM_MEMORY_AREA 3k - - SYSTEM_MEMORY total size is 3k - it is divided as following: - - TIME_MEMORY_AREA 8B ------------------------------------------------------------*/ - - - -/* - the maximum length of the message - the rest of the message shared - area will be dedicated to the dma lli tables -*/ -#define SEP_DRIVER_MAX_MESSAGE_SIZE_IN_BYTES (8 * 1024) - -/* the size of the message shared area in pages */ -#define SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES (8 * 1024) - -/* the size of the data pool static area in pages */ -#define SEP_DRIVER_STATIC_AREA_SIZE_IN_BYTES (4 * 1024) - -/* the size of the data pool shared area size in pages */ -#define SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES (12 * 1024) - -/* the size of the message shared area in pages */ -#define SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_SIZE_IN_BYTES (1024 * 5) - - -/* the size of the data pool shared area size in pages */ -#define SEP_DRIVER_FLOW_DMA_TABLES_AREA_SIZE_IN_BYTES (1024 * 4) - -/* system data (time, caller id etc') pool */ -#define SEP_DRIVER_SYSTEM_DATA_MEMORY_SIZE_IN_BYTES 100 - - -/* area size that is mapped - we map the MESSAGE AREA, STATIC POOL and - DATA POOL areas. area must be module 4k */ -#define SEP_DRIVER_MMMAP_AREA_SIZE (1024 * 24) - - -/*----------------------------------------------- - offsets of the areas starting from the shared area start address -*/ - -/* message area offset */ -#define SEP_DRIVER_MESSAGE_AREA_OFFSET_IN_BYTES 0 - -/* static pool area offset */ -#define SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES \ - (SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES) - -/* data pool area offset */ -#define SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES \ - (SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES + \ - SEP_DRIVER_STATIC_AREA_SIZE_IN_BYTES) - -/* synhronic dma tables area offset */ -#define SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES \ - (SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES + \ - SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES) - -/* sep driver flow dma tables area offset */ -#define SEP_DRIVER_FLOW_DMA_TABLES_AREA_OFFSET_IN_BYTES \ - (SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES + \ - SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_SIZE_IN_BYTES) - -/* system memory offset in bytes */ -#define SEP_DRIVER_SYSTEM_DATA_MEMORY_OFFSET_IN_BYTES \ - (SEP_DRIVER_FLOW_DMA_TABLES_AREA_OFFSET_IN_BYTES + \ - SEP_DRIVER_FLOW_DMA_TABLES_AREA_SIZE_IN_BYTES) - -/* offset of the time area */ -#define SEP_DRIVER_SYSTEM_TIME_MEMORY_OFFSET_IN_BYTES \ - (SEP_DRIVER_SYSTEM_DATA_MEMORY_OFFSET_IN_BYTES) - - - -/* start physical address of the SEP registers memory in HOST */ -#define SEP_IO_MEM_REGION_START_ADDRESS 0x80000000 - -/* size of the SEP registers memory region in HOST (for now 100 registers) */ -#define SEP_IO_MEM_REGION_SIZE (2 * 0x100000) - -/* define the number of IRQ for SEP interrupts */ -#define SEP_DIRVER_IRQ_NUM 1 - -/* maximum number of add buffers */ -#define SEP_MAX_NUM_ADD_BUFFERS 100 - -/* number of flows */ -#define SEP_DRIVER_NUM_FLOWS 4 - -/* maximum number of entries in flow table */ -#define SEP_DRIVER_MAX_FLOW_NUM_ENTRIES_IN_TABLE 25 - -/* offset of the num entries in the block length entry of the LLI */ -#define SEP_NUM_ENTRIES_OFFSET_IN_BITS 24 - -/* offset of the interrupt flag in the block length entry of the LLI */ -#define SEP_INT_FLAG_OFFSET_IN_BITS 31 - -/* mask for extracting data size from LLI */ -#define SEP_TABLE_DATA_SIZE_MASK 0xFFFFFF - -/* mask for entries after being shifted left */ -#define SEP_NUM_ENTRIES_MASK 0x7F - -/* default flow id */ -#define SEP_FREE_FLOW_ID 0xFFFFFFFF - -/* temp flow id used during cretiong of new flow until receiving - real flow id from sep */ -#define SEP_TEMP_FLOW_ID (SEP_DRIVER_NUM_FLOWS + 1) - -/* maximum add buffers message length in bytes */ -#define SEP_MAX_ADD_MESSAGE_LENGTH_IN_BYTES (7 * 4) - -/* maximum number of concurrent virtual buffers */ -#define SEP_MAX_VIRT_BUFFERS_CONCURRENT 100 - -/* the token that defines the start of time address */ -#define SEP_TIME_VAL_TOKEN 0x12345678 - -/* DEBUG LEVEL MASKS */ -#define SEP_DEBUG_LEVEL_BASIC 0x1 - -#define SEP_DEBUG_LEVEL_EXTENDED 0x4 - - -/* Debug helpers */ - -#define dbg(fmt, args...) \ -do {\ - if (debug & SEP_DEBUG_LEVEL_BASIC) \ - printk(KERN_DEBUG fmt, ##args); \ -} while(0); - -#define edbg(fmt, args...) \ -do { \ - if (debug & SEP_DEBUG_LEVEL_EXTENDED) \ - printk(KERN_DEBUG fmt, ##args); \ -} while(0); - - - -#endif diff --git a/drivers/staging/sep/sep_driver_hw_defs.h b/drivers/staging/sep/sep_driver_hw_defs.h deleted file mode 100644 index ea6abd8..0000000 --- a/drivers/staging/sep/sep_driver_hw_defs.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - * - * sep_driver_hw_defs.h - Security Processor Driver hardware definitions - * - * Copyright(c) 2009 Intel Corporation. All rights reserved. - * Copyright(c) 2009 Discretix. 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 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. - * - * CONTACTS: - * - * Mark Allyn mark.a.allyn@intel.com - * - * CHANGES: - * - * 2009.06.26 Initial publish - * - */ - -#ifndef SEP_DRIVER_HW_DEFS__H -#define SEP_DRIVER_HW_DEFS__H - -/*--------------------------------------------------------------------------*/ -/* Abstract: HW Registers Defines. */ -/* */ -/* Note: This file was automatically created !!! */ -/* DO NOT EDIT THIS FILE !!! */ -/*--------------------------------------------------------------------------*/ - - -/* cf registers */ -#define HW_R0B_ADDR_0_REG_ADDR 0x0000UL -#define HW_R0B_ADDR_1_REG_ADDR 0x0004UL -#define HW_R0B_ADDR_2_REG_ADDR 0x0008UL -#define HW_R0B_ADDR_3_REG_ADDR 0x000cUL -#define HW_R0B_ADDR_4_REG_ADDR 0x0010UL -#define HW_R0B_ADDR_5_REG_ADDR 0x0014UL -#define HW_R0B_ADDR_6_REG_ADDR 0x0018UL -#define HW_R0B_ADDR_7_REG_ADDR 0x001cUL -#define HW_R0B_ADDR_8_REG_ADDR 0x0020UL -#define HW_R2B_ADDR_0_REG_ADDR 0x0080UL -#define HW_R2B_ADDR_1_REG_ADDR 0x0084UL -#define HW_R2B_ADDR_2_REG_ADDR 0x0088UL -#define HW_R2B_ADDR_3_REG_ADDR 0x008cUL -#define HW_R2B_ADDR_4_REG_ADDR 0x0090UL -#define HW_R2B_ADDR_5_REG_ADDR 0x0094UL -#define HW_R2B_ADDR_6_REG_ADDR 0x0098UL -#define HW_R2B_ADDR_7_REG_ADDR 0x009cUL -#define HW_R2B_ADDR_8_REG_ADDR 0x00a0UL -#define HW_R3B_REG_ADDR 0x00C0UL -#define HW_R4B_REG_ADDR 0x0100UL -#define HW_CSA_ADDR_0_REG_ADDR 0x0140UL -#define HW_CSA_ADDR_1_REG_ADDR 0x0144UL -#define HW_CSA_ADDR_2_REG_ADDR 0x0148UL -#define HW_CSA_ADDR_3_REG_ADDR 0x014cUL -#define HW_CSA_ADDR_4_REG_ADDR 0x0150UL -#define HW_CSA_ADDR_5_REG_ADDR 0x0154UL -#define HW_CSA_ADDR_6_REG_ADDR 0x0158UL -#define HW_CSA_ADDR_7_REG_ADDR 0x015cUL -#define HW_CSA_ADDR_8_REG_ADDR 0x0160UL -#define HW_CSA_REG_ADDR 0x0140UL -#define HW_SINB_REG_ADDR 0x0180UL -#define HW_SOUTB_REG_ADDR 0x0184UL -#define HW_PKI_CONTROL_REG_ADDR 0x01C0UL -#define HW_PKI_STATUS_REG_ADDR 0x01C4UL -#define HW_PKI_BUSY_REG_ADDR 0x01C8UL -#define HW_PKI_A_1025_REG_ADDR 0x01CCUL -#define HW_PKI_SDMA_CTL_REG_ADDR 0x01D0UL -#define HW_PKI_SDMA_OFFSET_REG_ADDR 0x01D4UL -#define HW_PKI_SDMA_POINTERS_REG_ADDR 0x01D8UL -#define HW_PKI_SDMA_DLENG_REG_ADDR 0x01DCUL -#define HW_PKI_SDMA_EXP_POINTERS_REG_ADDR 0x01E0UL -#define HW_PKI_SDMA_RES_POINTERS_REG_ADDR 0x01E4UL -#define HW_PKI_CLR_REG_ADDR 0x01E8UL -#define HW_PKI_SDMA_BUSY_REG_ADDR 0x01E8UL -#define HW_PKI_SDMA_FIRST_EXP_N_REG_ADDR 0x01ECUL -#define HW_PKI_SDMA_MUL_BY1_REG_ADDR 0x01F0UL -#define HW_PKI_SDMA_RMUL_SEL_REG_ADDR 0x01F4UL -#define HW_DES_KEY_0_REG_ADDR 0x0208UL -#define HW_DES_KEY_1_REG_ADDR 0x020CUL -#define HW_DES_KEY_2_REG_ADDR 0x0210UL -#define HW_DES_KEY_3_REG_ADDR 0x0214UL -#define HW_DES_KEY_4_REG_ADDR 0x0218UL -#define HW_DES_KEY_5_REG_ADDR 0x021CUL -#define HW_DES_CONTROL_0_REG_ADDR 0x0220UL -#define HW_DES_CONTROL_1_REG_ADDR 0x0224UL -#define HW_DES_IV_0_REG_ADDR 0x0228UL -#define HW_DES_IV_1_REG_ADDR 0x022CUL -#define HW_AES_KEY_0_ADDR_0_REG_ADDR 0x0400UL -#define HW_AES_KEY_0_ADDR_1_REG_ADDR 0x0404UL -#define HW_AES_KEY_0_ADDR_2_REG_ADDR 0x0408UL -#define HW_AES_KEY_0_ADDR_3_REG_ADDR 0x040cUL -#define HW_AES_KEY_0_ADDR_4_REG_ADDR 0x0410UL -#define HW_AES_KEY_0_ADDR_5_REG_ADDR 0x0414UL -#define HW_AES_KEY_0_ADDR_6_REG_ADDR 0x0418UL -#define HW_AES_KEY_0_ADDR_7_REG_ADDR 0x041cUL -#define HW_AES_KEY_0_REG_ADDR 0x0400UL -#define HW_AES_IV_0_ADDR_0_REG_ADDR 0x0440UL -#define HW_AES_IV_0_ADDR_1_REG_ADDR 0x0444UL -#define HW_AES_IV_0_ADDR_2_REG_ADDR 0x0448UL -#define HW_AES_IV_0_ADDR_3_REG_ADDR 0x044cUL -#define HW_AES_IV_0_REG_ADDR 0x0440UL -#define HW_AES_CTR1_ADDR_0_REG_ADDR 0x0460UL -#define HW_AES_CTR1_ADDR_1_REG_ADDR 0x0464UL -#define HW_AES_CTR1_ADDR_2_REG_ADDR 0x0468UL -#define HW_AES_CTR1_ADDR_3_REG_ADDR 0x046cUL -#define HW_AES_CTR1_REG_ADDR 0x0460UL -#define HW_AES_SK_REG_ADDR 0x0478UL -#define HW_AES_MAC_OK_REG_ADDR 0x0480UL -#define HW_AES_PREV_IV_0_ADDR_0_REG_ADDR 0x0490UL -#define HW_AES_PREV_IV_0_ADDR_1_REG_ADDR 0x0494UL -#define HW_AES_PREV_IV_0_ADDR_2_REG_ADDR 0x0498UL -#define HW_AES_PREV_IV_0_ADDR_3_REG_ADDR 0x049cUL -#define HW_AES_PREV_IV_0_REG_ADDR 0x0490UL -#define HW_AES_CONTROL_REG_ADDR 0x04C0UL -#define HW_HASH_H0_REG_ADDR 0x0640UL -#define HW_HASH_H1_REG_ADDR 0x0644UL -#define HW_HASH_H2_REG_ADDR 0x0648UL -#define HW_HASH_H3_REG_ADDR 0x064CUL -#define HW_HASH_H4_REG_ADDR 0x0650UL -#define HW_HASH_H5_REG_ADDR 0x0654UL -#define HW_HASH_H6_REG_ADDR 0x0658UL -#define HW_HASH_H7_REG_ADDR 0x065CUL -#define HW_HASH_H8_REG_ADDR 0x0660UL -#define HW_HASH_H9_REG_ADDR 0x0664UL -#define HW_HASH_H10_REG_ADDR 0x0668UL -#define HW_HASH_H11_REG_ADDR 0x066CUL -#define HW_HASH_H12_REG_ADDR 0x0670UL -#define HW_HASH_H13_REG_ADDR 0x0674UL -#define HW_HASH_H14_REG_ADDR 0x0678UL -#define HW_HASH_H15_REG_ADDR 0x067CUL -#define HW_HASH_CONTROL_REG_ADDR 0x07C0UL -#define HW_HASH_PAD_EN_REG_ADDR 0x07C4UL -#define HW_HASH_PAD_CFG_REG_ADDR 0x07C8UL -#define HW_HASH_CUR_LEN_0_REG_ADDR 0x07CCUL -#define HW_HASH_CUR_LEN_1_REG_ADDR 0x07D0UL -#define HW_HASH_CUR_LEN_2_REG_ADDR 0x07D4UL -#define HW_HASH_CUR_LEN_3_REG_ADDR 0x07D8UL -#define HW_HASH_PARAM_REG_ADDR 0x07DCUL -#define HW_HASH_INT_BUSY_REG_ADDR 0x07E0UL -#define HW_HASH_SW_RESET_REG_ADDR 0x07E4UL -#define HW_HASH_ENDIANESS_REG_ADDR 0x07E8UL -#define HW_HASH_DATA_REG_ADDR 0x07ECUL -#define HW_DRNG_CONTROL_REG_ADDR 0x0800UL -#define HW_DRNG_VALID_REG_ADDR 0x0804UL -#define HW_DRNG_DATA_REG_ADDR 0x0808UL -#define HW_RND_SRC_EN_REG_ADDR 0x080CUL -#define HW_AES_CLK_ENABLE_REG_ADDR 0x0810UL -#define HW_DES_CLK_ENABLE_REG_ADDR 0x0814UL -#define HW_HASH_CLK_ENABLE_REG_ADDR 0x0818UL -#define HW_PKI_CLK_ENABLE_REG_ADDR 0x081CUL -#define HW_CLK_STATUS_REG_ADDR 0x0824UL -#define HW_CLK_ENABLE_REG_ADDR 0x0828UL -#define HW_DRNG_SAMPLE_REG_ADDR 0x0850UL -#define HW_RND_SRC_CTL_REG_ADDR 0x0858UL -#define HW_CRYPTO_CTL_REG_ADDR 0x0900UL -#define HW_CRYPTO_STATUS_REG_ADDR 0x090CUL -#define HW_CRYPTO_BUSY_REG_ADDR 0x0910UL -#define HW_AES_BUSY_REG_ADDR 0x0914UL -#define HW_DES_BUSY_REG_ADDR 0x0918UL -#define HW_HASH_BUSY_REG_ADDR 0x091CUL -#define HW_CONTENT_REG_ADDR 0x0924UL -#define HW_VERSION_REG_ADDR 0x0928UL -#define HW_CONTEXT_ID_REG_ADDR 0x0930UL -#define HW_DIN_BUFFER_REG_ADDR 0x0C00UL -#define HW_DIN_MEM_DMA_BUSY_REG_ADDR 0x0c20UL -#define HW_SRC_LLI_MEM_ADDR_REG_ADDR 0x0c24UL -#define HW_SRC_LLI_WORD0_REG_ADDR 0x0C28UL -#define HW_SRC_LLI_WORD1_REG_ADDR 0x0C2CUL -#define HW_SRAM_SRC_ADDR_REG_ADDR 0x0c30UL -#define HW_DIN_SRAM_BYTES_LEN_REG_ADDR 0x0c34UL -#define HW_DIN_SRAM_DMA_BUSY_REG_ADDR 0x0C38UL -#define HW_WRITE_ALIGN_REG_ADDR 0x0C3CUL -#define HW_OLD_DATA_REG_ADDR 0x0C48UL -#define HW_WRITE_ALIGN_LAST_REG_ADDR 0x0C4CUL -#define HW_DOUT_BUFFER_REG_ADDR 0x0C00UL -#define HW_DST_LLI_WORD0_REG_ADDR 0x0D28UL -#define HW_DST_LLI_WORD1_REG_ADDR 0x0D2CUL -#define HW_DST_LLI_MEM_ADDR_REG_ADDR 0x0D24UL -#define HW_DOUT_MEM_DMA_BUSY_REG_ADDR 0x0D20UL -#define HW_SRAM_DEST_ADDR_REG_ADDR 0x0D30UL -#define HW_DOUT_SRAM_BYTES_LEN_REG_ADDR 0x0D34UL -#define HW_DOUT_SRAM_DMA_BUSY_REG_ADDR 0x0D38UL -#define HW_READ_ALIGN_REG_ADDR 0x0D3CUL -#define HW_READ_LAST_DATA_REG_ADDR 0x0D44UL -#define HW_RC4_THRU_CPU_REG_ADDR 0x0D4CUL -#define HW_AHB_SINGLE_REG_ADDR 0x0E00UL -#define HW_SRAM_DATA_REG_ADDR 0x0F00UL -#define HW_SRAM_ADDR_REG_ADDR 0x0F04UL -#define HW_SRAM_DATA_READY_REG_ADDR 0x0F08UL -#define HW_HOST_IRR_REG_ADDR 0x0A00UL -#define HW_HOST_IMR_REG_ADDR 0x0A04UL -#define HW_HOST_ICR_REG_ADDR 0x0A08UL -#define HW_HOST_SEP_SRAM_THRESHOLD_REG_ADDR 0x0A10UL -#define HW_HOST_SEP_BUSY_REG_ADDR 0x0A14UL -#define HW_HOST_SEP_LCS_REG_ADDR 0x0A18UL -#define HW_HOST_CC_SW_RST_REG_ADDR 0x0A40UL -#define HW_HOST_SEP_SW_RST_REG_ADDR 0x0A44UL -#define HW_HOST_FLOW_DMA_SW_INT0_REG_ADDR 0x0A80UL -#define HW_HOST_FLOW_DMA_SW_INT1_REG_ADDR 0x0A84UL -#define HW_HOST_FLOW_DMA_SW_INT2_REG_ADDR 0x0A88UL -#define HW_HOST_FLOW_DMA_SW_INT3_REG_ADDR 0x0A8cUL -#define HW_HOST_FLOW_DMA_SW_INT4_REG_ADDR 0x0A90UL -#define HW_HOST_FLOW_DMA_SW_INT5_REG_ADDR 0x0A94UL -#define HW_HOST_FLOW_DMA_SW_INT6_REG_ADDR 0x0A98UL -#define HW_HOST_FLOW_DMA_SW_INT7_REG_ADDR 0x0A9cUL -#define HW_HOST_SEP_HOST_GPR0_REG_ADDR 0x0B00UL -#define HW_HOST_SEP_HOST_GPR1_REG_ADDR 0x0B04UL -#define HW_HOST_SEP_HOST_GPR2_REG_ADDR 0x0B08UL -#define HW_HOST_SEP_HOST_GPR3_REG_ADDR 0x0B0CUL -#define HW_HOST_HOST_SEP_GPR0_REG_ADDR 0x0B80UL -#define HW_HOST_HOST_SEP_GPR1_REG_ADDR 0x0B84UL -#define HW_HOST_HOST_SEP_GPR2_REG_ADDR 0x0B88UL -#define HW_HOST_HOST_SEP_GPR3_REG_ADDR 0x0B8CUL -#define HW_HOST_HOST_ENDIAN_REG_ADDR 0x0B90UL -#define HW_HOST_HOST_COMM_CLK_EN_REG_ADDR 0x0B94UL -#define HW_CLR_SRAM_BUSY_REG_REG_ADDR 0x0F0CUL -#define HW_CC_SRAM_BASE_ADDRESS 0x5800UL - -#endif /* ifndef HW_DEFS */ -- cgit v0.10.2 From 07cda511c78db79974f56b277b3704bfc6bba711 Mon Sep 17 00:00:00 2001 From: "Luck, Tony" Date: Thu, 12 Aug 2010 12:16:43 -0700 Subject: serial: print early console device address in hex Device addresses are usually printed in hex. Signed-off-by: Tony Luck Cc: Andrew Morton Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/serial/8250_early.c b/drivers/serial/8250_early.c index b745792..eaafb98 100644 --- a/drivers/serial/8250_early.c +++ b/drivers/serial/8250_early.c @@ -203,13 +203,13 @@ static int __init parse_options(struct early_serial8250_device *device, if (mmio || mmio32) printk(KERN_INFO - "Early serial console at MMIO%s 0x%llu (options '%s')\n", + "Early serial console at MMIO%s 0x%llx (options '%s')\n", mmio32 ? "32" : "", (unsigned long long)port->mapbase, device->options); else printk(KERN_INFO - "Early serial console at I/O port 0x%lu (options '%s')\n", + "Early serial console at I/O port 0x%lx (options '%s')\n", port->iobase, device->options); -- cgit v0.10.2 From f64ac9830b2a2455208ee023f6bac480ae159db4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 12 Aug 2010 13:48:57 -0700 Subject: ip2: remove unneeded NULL check We don't pass NULL tty pointers to the close function, and anyway we already dereferenced it at this point. This check can be removed. Signed-off-by: Dan Carpenter Cc: "Michael H. Warfield" Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 07f3ea3..8fa041e 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -1650,7 +1650,7 @@ ip2_close( PTTY tty, struct file *pFile ) /* disable DSS reporting */ i2QueueCommands(PTYPE_INLINE, pCh, 100, 4, CMD_DCD_NREP, CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP); - if ( !tty || (tty->termios->c_cflag & HUPCL) ) { + if (tty->termios->c_cflag & HUPCL) { i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN); pCh->dataSetOut &= ~(I2_DTR | I2_RTS); i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25)); -- cgit v0.10.2 From 05254a207a255e1a76f9b349a783b5016b874d72 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 12 Aug 2010 13:48:59 -0700 Subject: ip2: return -EFAULT on copy_to_user errors copy_to_user() returns the number of bytes remaining but we want to return a negative error code on errors. Signed-off-by: Dan Carpenter Cc: "Michael H. Warfield" Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 8fa041e..d4b71e8 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -2930,6 +2930,8 @@ ip2_ipl_ioctl (struct file *pFile, UINT cmd, ULONG arg ) if ( pCh ) { rc = copy_to_user(argp, pCh, sizeof(i2ChanStr)); + if (rc) + rc = -EFAULT; } else { rc = -ENODEV; } -- cgit v0.10.2 From 49bf7eaffc0c252ab2a2cc8f1bf8c0077e778704 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 11 Aug 2010 20:00:09 +0200 Subject: rocket: add a mutex_unlock() This path needs a mutex_unlock(). This is stuff from the bkl to mutex transition. Signed-off-by: Dan Carpenter Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index 79c3bc6..7c79d24 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -1244,6 +1244,7 @@ static int set_config(struct tty_struct *tty, struct r_port *info, } info->flags = ((info->flags & ~ROCKET_USR_MASK) | (new_serial.flags & ROCKET_USR_MASK)); configure_r_port(tty, info, NULL); + mutex_unlock(&info->port.mutex); return 0; } -- cgit v0.10.2 From 80d04f22b0869a1145b36a90a83a79603ac92be8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 11 Aug 2010 20:01:46 +0200 Subject: synclink: add mutex_unlock() on error path There is a path which still holds its mutex here. Signed-off-by: Dan Carpenter Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index fef80cf..e63b830 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -691,8 +691,10 @@ static int open(struct tty_struct *tty, struct file *filp) if (info->port.count == 1) { /* 1st open on this device, init hardware */ retval = startup(info); - if (retval < 0) + if (retval < 0) { + mutex_unlock(&info->port.mutex); goto cleanup; + } } mutex_unlock(&info->port.mutex); retval = block_til_ready(tty, filp, info); -- cgit v0.10.2 From 5d56356a2c9f5e96efe7a095cbf9b6fee8265d22 Mon Sep 17 00:00:00 2001 From: Kulikov Vasiliy Date: Sun, 1 Aug 2010 10:29:06 +0400 Subject: 68328serial: check return value of copy_*_user() instead of access_ok() As copy_*_user() calls access_ok() it should not be called explicitly. Signed-off-by: Kulikov Vasiliy Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c index 7356a56..be0ebce 100644 --- a/drivers/serial/68328serial.c +++ b/drivers/serial/68328serial.c @@ -869,7 +869,9 @@ static int get_serial_info(struct m68k_serial * info, tmp.close_delay = info->close_delay; tmp.closing_wait = info->closing_wait; tmp.custom_divisor = info->custom_divisor; - copy_to_user(retinfo,&tmp,sizeof(*retinfo)); + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + return -EFAULT; + return 0; } @@ -882,7 +884,8 @@ static int set_serial_info(struct m68k_serial * info, if (!new_info) return -EFAULT; - copy_from_user(&new_serial,new_info,sizeof(new_serial)); + if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) + return -EFAULT; old_info = *info; if (!capable(CAP_SYS_ADMIN)) { @@ -943,8 +946,7 @@ static int get_lsr_info(struct m68k_serial * info, unsigned int *value) status = 0; #endif local_irq_restore(flags); - put_user(status,value); - return 0; + return put_user(status, value); } /* @@ -999,27 +1001,18 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, send_break(info, arg ? arg*(100) : 250); return 0; case TIOCGSERIAL: - if (access_ok(VERIFY_WRITE, (void *) arg, - sizeof(struct serial_struct))) - return get_serial_info(info, - (struct serial_struct *) arg); - return -EFAULT; + return get_serial_info(info, + (struct serial_struct *) arg); case TIOCSSERIAL: return set_serial_info(info, (struct serial_struct *) arg); case TIOCSERGETLSR: /* Get line status register */ - if (access_ok(VERIFY_WRITE, (void *) arg, - sizeof(unsigned int))) - return get_lsr_info(info, (unsigned int *) arg); - return -EFAULT; + return get_lsr_info(info, (unsigned int *) arg); case TIOCSERGSTRUCT: - if (!access_ok(VERIFY_WRITE, (void *) arg, - sizeof(struct m68k_serial))) + if (copy_to_user((struct m68k_serial *) arg, + info, sizeof(struct m68k_serial))) return -EFAULT; - copy_to_user((struct m68k_serial *) arg, - info, sizeof(struct m68k_serial)); return 0; - default: return -ENOIOCTLCMD; } -- cgit v0.10.2 From 9a887162be81bd21ea8495e0a57b46ab1d77d205 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 12 Aug 2010 09:59:58 +0200 Subject: USB: uvc_v4l2: cleanup test for end of loop We're trying to test for the the end of the loop here. "format" is never NULL. We don't know what "format->fcc" is because we're past the end of the loop and I think "fmt->fmt.pix.pixelformat" comes from the user so we don't know what that is either. It works, but it's cleaner to just test to see if (i == ARRAY_SIZE(uvc_formats). Signed-off-by: Dan Carpenter Acked-by: Laurent Pinchart Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/gadget/uvc_v4l2.c b/drivers/usb/gadget/uvc_v4l2.c index 2dcffda..5e807f0 100644 --- a/drivers/usb/gadget/uvc_v4l2.c +++ b/drivers/usb/gadget/uvc_v4l2.c @@ -94,7 +94,7 @@ uvc_v4l2_set_format(struct uvc_video *video, struct v4l2_format *fmt) break; } - if (format == NULL || format->fcc != fmt->fmt.pix.pixelformat) { + if (i == ARRAY_SIZE(uvc_formats)) { printk(KERN_INFO "Unsupported format 0x%08x.\n", fmt->fmt.pix.pixelformat); return -EINVAL; -- cgit v0.10.2 From 76078dc4fc389185fe467d33428f259ea9e69807 Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Fri, 6 Aug 2010 18:49:21 +0400 Subject: USB: option: add Celot CT-650 Signed-off-by: Michael Tokarev Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 9fc6ea2..adcbdb9 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -365,6 +365,10 @@ static void option_instat_callback(struct urb *urb); #define OLIVETTI_VENDOR_ID 0x0b3c #define OLIVETTI_PRODUCT_OLICARD100 0xc000 +/* Celot products */ +#define CELOT_VENDOR_ID 0x211f +#define CELOT_PRODUCT_CT680M 0x6801 + /* some devices interfaces need special handling due to a number of reasons */ enum option_blacklist_reason { OPTION_BLACKLIST_NONE = 0, @@ -887,10 +891,9 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100F) }, { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1011)}, { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1012)}, - { USB_DEVICE(CINTERION_VENDOR_ID, 0x0047) }, - { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) }, + { USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */ { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); -- cgit v0.10.2 From ebb8a4e48722c8f5e04a6490b197d2fbc894a0f6 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 5 Aug 2010 17:53:57 -0400 Subject: USB: isp1760: use a write barrier to ensure proper ndelay timing The ISP1760 has some timing requirements where it has to delay a short period after a write to a register has started. However, this delay is from the time the write hits the USB chip (the ISP1760), not from the time where the processor started processing the write. So on a quick enough processor, it is sometimes possible for the write to not hit the device before we start delaying, and we then violate the part's timing requirements, so things stop working. To avoid all this, insert a write barrier after the register write and before the timing delay/register read so we can guarantee we only start counting time after the write has hit the device. Signed-off-by: Michael Hennerich Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c index d1a3dfc..bdba8c5 100644 --- a/drivers/usb/host/isp1760-hcd.c +++ b/drivers/usb/host/isp1760-hcd.c @@ -829,6 +829,7 @@ static void enqueue_an_ATL_packet(struct usb_hcd *hcd, struct isp1760_qh *qh, * almost immediately. With ISP1761, this register requires a delay of * 195ns between a write and subsequent read (see section 15.1.1.3). */ + mmiowb(); ndelay(195); skip_map = isp1760_readl(hcd->regs + HC_ATL_PTD_SKIPMAP_REG); @@ -870,6 +871,7 @@ static void enqueue_an_INT_packet(struct usb_hcd *hcd, struct isp1760_qh *qh, * almost immediately. With ISP1761, this register requires a delay of * 195ns between a write and subsequent read (see section 15.1.1.3). */ + mmiowb(); ndelay(195); skip_map = isp1760_readl(hcd->regs + HC_INT_PTD_SKIPMAP_REG); -- cgit v0.10.2 From 0eee6a2b2a52e17066a572d30ad2805d3ebc7508 Mon Sep 17 00:00:00 2001 From: Ross Burton Date: Fri, 6 Aug 2010 16:36:39 +0100 Subject: USB: add device IDs for igotu to navman I recently bought a i-gotU USB GPS, and whilst hunting around for linux support discovered this post by you back in 2009: http://kerneltrap.org/mailarchive/linux-usb/2009/3/12/5148644 >Try the navman driver instead. You can either add the device id to the > driver and rebuild it, or do this before you plug the device in: > modprobe navman > echo -n "0x0df7 0x0900" > /sys/bus/usb-serial/drivers/navman/new_id > > and then plug your device in and see if that works. I can confirm that the navman driver works with the right device IDs on my i-gotU GT-600, which has the same device IDs. Attached is a patch adding the IDs. From: Ross Burton Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c index a6b207c..1f00f24 100644 --- a/drivers/usb/serial/navman.c +++ b/drivers/usb/serial/navman.c @@ -25,6 +25,7 @@ static int debug; static const struct usb_device_id id_table[] = { { USB_DEVICE(0x0a99, 0x0001) }, /* Talon Technology device */ + { USB_DEVICE(0x0df7, 0x0900) }, /* Mobile Action i-gotU */ { }, }; MODULE_DEVICE_TABLE(usb, id_table); -- cgit v0.10.2 From d92a3ca689257c6bec94e026538782c280afaaab Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Sat, 7 Aug 2010 16:20:35 +0800 Subject: USB: serial: fix leak of usb serial module refrence count The patch with title below makes reference count of usb serial module always more than one after driver is bound. USB-BKL: Remove BKL use for usb serial driver probing In fact, the patch above only replaces lock_kernel() with try_module_get() , and does not use module_put() to do what unlock_kernel() did, so casue leak of reference count of usb serial module and the module can not be unloaded after serial driver is bound with device. This patch fixes the issue, also simplifies such things: -only call try_module_get() once in the entry of usb_serial_probe() -only call module_put() once in the exit of usb_serial_probe Signed-off-by: Ming Lei Cc: Johan Hovold Cc: Andi Kleen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 2a982e6..7a2177c 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -736,6 +736,7 @@ int usb_serial_probe(struct usb_interface *interface, serial = create_serial(dev, interface, type); if (!serial) { + module_put(type->driver.owner); dev_err(&interface->dev, "%s - out of memory\n", __func__); return -ENOMEM; } @@ -746,11 +747,11 @@ int usb_serial_probe(struct usb_interface *interface, id = get_iface_id(type, interface); retval = type->probe(serial, id); - module_put(type->driver.owner); if (retval) { dbg("sub driver rejected device"); kfree(serial); + module_put(type->driver.owner); return retval; } } @@ -822,6 +823,7 @@ int usb_serial_probe(struct usb_interface *interface, if (num_bulk_in == 0 || num_bulk_out == 0) { dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n"); kfree(serial); + module_put(type->driver.owner); return -ENODEV; } } @@ -835,22 +837,15 @@ int usb_serial_probe(struct usb_interface *interface, dev_err(&interface->dev, "Generic device with no bulk out, not allowed.\n"); kfree(serial); + module_put(type->driver.owner); return -EIO; } } #endif if (!num_ports) { /* if this device type has a calc_num_ports function, call it */ - if (type->calc_num_ports) { - if (!try_module_get(type->driver.owner)) { - dev_err(&interface->dev, - "module get failed, exiting\n"); - kfree(serial); - return -EIO; - } + if (type->calc_num_ports) num_ports = type->calc_num_ports(serial); - module_put(type->driver.owner); - } if (!num_ports) num_ports = type->num_ports; } @@ -1039,13 +1034,7 @@ int usb_serial_probe(struct usb_interface *interface, /* if this device type has an attach function, call it */ if (type->attach) { - if (!try_module_get(type->driver.owner)) { - dev_err(&interface->dev, - "module get failed, exiting\n"); - goto probe_error; - } retval = type->attach(serial); - module_put(type->driver.owner); if (retval < 0) goto probe_error; serial->attached = 1; @@ -1088,10 +1077,12 @@ int usb_serial_probe(struct usb_interface *interface, exit: /* success */ usb_set_intfdata(interface, serial); + module_put(type->driver.owner); return 0; probe_error: usb_serial_put(serial); + module_put(type->driver.owner); return -EIO; } EXPORT_SYMBOL_GPL(usb_serial_probe); -- cgit v0.10.2 From f36ecd5de93e4c85a9e3d25100c6e233155b12e5 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 9 Aug 2010 15:55:32 +0200 Subject: USB: pl2303: New vendor and product id Add support for the Zeagle N2iTiON3 dive computer interface. Since Zeagle devices are actually manufactured by Seiko, this patch will support other Seiko based models as well. Signed-off-by: Jef Driesen Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 6b60018..c98f0fb 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -86,6 +86,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) }, { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) }, + { USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) }, { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) }, { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) }, diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index a871645..43eb9bd 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -128,6 +128,10 @@ #define CRESSI_VENDOR_ID 0x04b8 #define CRESSI_EDY_PRODUCT_ID 0x0521 +/* Zeagle dive computer interface */ +#define ZEAGLE_VENDOR_ID 0x04b8 +#define ZEAGLE_N2ITION3_PRODUCT_ID 0x0522 + /* Sony, USB data cable for CMD-Jxx mobile phones */ #define SONY_VENDOR_ID 0x054c #define SONY_QN3USB_PRODUCT_ID 0x0437 -- cgit v0.10.2 From 72916791cbeb9cc607ae620cfba207dea481cd76 Mon Sep 17 00:00:00 2001 From: Craig Shelley Date: Wed, 18 Aug 2010 22:13:39 +0100 Subject: USB: CP210x Fix Break On/Off The definitions for BREAK_ON and BREAK_OFF are inverted, causing break requests to fail. This patch sets BREAK_ON and BREAK_OFF to the correct values. Signed-off-by: Craig Shelley Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 2bef441..80bf833 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -222,8 +222,8 @@ static struct usb_serial_driver cp210x_device = { #define BITS_STOP_2 0x0002 /* CP210X_SET_BREAK */ -#define BREAK_ON 0x0000 -#define BREAK_OFF 0x0001 +#define BREAK_ON 0x0001 +#define BREAK_OFF 0x0000 /* CP210X_(SET_MHS|GET_MDMSTS) */ #define CONTROL_DTR 0x0001 -- cgit v0.10.2 From d1ab903d2552b2362339b19203c7f01c797cb316 Mon Sep 17 00:00:00 2001 From: Michael Wileczka Date: Wed, 18 Aug 2010 07:14:37 -0700 Subject: USB: ftdi_sio: fix endianess of max packet size The USB max packet size (always little-endian) was not being byte swapped on big-endian systems. Applicable since [USB: ftdi_sio: fix hi-speed device packet size calculation] approx 2.6.31 Signed-off-by: Michael Wileczka Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index eb12d9b..e04a416 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1376,7 +1376,7 @@ static void ftdi_set_max_packet_size(struct usb_serial_port *port) } /* set max packet size based on descriptor */ - priv->max_packet_size = ep_desc->wMaxPacketSize; + priv->max_packet_size = le16_to_cpu(ep_desc->wMaxPacketSize); dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size); } -- cgit v0.10.2 From 0827a9ff2bbcbb03c33f1a6eb283fe051059482c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 17 Aug 2010 15:15:37 -0700 Subject: USB: io_ti: check firmware version before updating If we can't read the firmware for a device from the disk, and yet the device already has a valid firmware image in it, we don't want to replace the firmware with something invalid. So check the version number to be less than the current one to verify this is the correct thing to do. Reported-by: Chris Beauchamp Tested-by: Chris Beauchamp Cc: Alan Stern Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index dc47f98..c3f27c3 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -1151,7 +1151,7 @@ static int download_fw(struct edgeport_serial *serial) /* Check if we have an old version in the I2C and update if necessary */ - if (download_cur_ver != download_new_ver) { + if (download_cur_ver < download_new_ver) { dbg("%s - Update I2C dld from %d.%d to %d.%d", __func__, firmware_version->Ver_Major, -- cgit v0.10.2 From 96f2a34d2cec71d59014be9ecd7a038435e88584 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 17 Aug 2010 09:41:29 +0800 Subject: USB: r8a66597-udc: return -ENOMEM if kzalloc() fails Signed-off-by: Axel Lin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 70a8178..2456ccd 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1557,6 +1557,7 @@ static int __init r8a66597_probe(struct platform_device *pdev) /* initialize ucd */ r8a66597 = kzalloc(sizeof(struct r8a66597), GFP_KERNEL); if (r8a66597 == NULL) { + ret = -ENOMEM; printk(KERN_ERR "kzalloc error\n"); goto clean_up; } -- cgit v0.10.2 From 175230587bcca6dee0a1d6832a8a2138e32ab6ab Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Thu, 5 Aug 2010 17:01:05 -0400 Subject: USB: ssu100: add locking for port private data in ssu100 Signed-off-by: Bill Pemberton Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 6e82d4f..2826f01 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -99,6 +99,7 @@ static struct usb_driver ssu100_driver = { }; struct ssu100_port_private { + spinlock_t status_lock; u8 shadowLSR; u8 shadowMSR; wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ @@ -333,6 +334,7 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) struct ssu100_port_private *priv = usb_get_serial_port_data(port); u8 *data; int result; + unsigned long flags; dbg("%s - port %d", __func__, port->number); @@ -350,11 +352,13 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) return result; } + spin_lock_irqsave(&priv->status_lock, flags); priv->shadowLSR = data[0] & (SERIAL_LSR_OE | SERIAL_LSR_PE | SERIAL_LSR_FE | SERIAL_LSR_BI); priv->shadowMSR = data[1] & (SERIAL_MSR_CTS | SERIAL_MSR_DSR | SERIAL_MSR_RI | SERIAL_MSR_CD); + spin_unlock_irqrestore(&priv->status_lock, flags); kfree(data); @@ -455,6 +459,7 @@ static void ssu100_set_max_packet_size(struct usb_serial_port *port) unsigned num_endpoints; int i; + unsigned long flags; num_endpoints = interface->cur_altsetting->desc.bNumEndpoints; dev_info(&udev->dev, "Number of endpoints %d\n", num_endpoints); @@ -466,7 +471,9 @@ static void ssu100_set_max_packet_size(struct usb_serial_port *port) } /* set max packet size based on descriptor */ + spin_lock_irqsave(&priv->status_lock, flags); priv->max_packet_size = ep_desc->wMaxPacketSize; + spin_unlock_irqrestore(&priv->status_lock, flags); dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size); } @@ -485,9 +492,9 @@ static int ssu100_attach(struct usb_serial *serial) return -ENOMEM; } + spin_lock_init(&priv->status_lock); init_waitqueue_head(&priv->delta_msr_wait); usb_set_serial_port_data(port, priv); - ssu100_set_max_packet_size(port); return ssu100_initdevice(serial->dev); -- cgit v0.10.2 From 9b2cef31f2823558eb92a35624d37439599f3f9f Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Thu, 5 Aug 2010 17:01:06 -0400 Subject: USB: ssu100: refine process_packet in ssu100 The status information does not appear at the start of each incoming packet so the check for len < 4 at the start of ssu100_process_packet is wrong. Remove it. Signed-off-by: Bill Pemberton Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 2826f01..c719388 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -575,12 +575,8 @@ static int ssu100_process_packet(struct tty_struct *tty, dbg("%s - port %d", __func__, port->number); - if (len < 4) { - dbg("%s - malformed packet", __func__); - return 0; - } - - if ((packet[0] == 0x1b) && (packet[1] == 0x1b) && + if ((len >= 4) && + (packet[0] == 0x1b) && (packet[1] == 0x1b) && ((packet[2] == 0x00) || (packet[2] == 0x01))) { if (packet[2] == 0x00) priv->shadowLSR = packet[3] & (SERIAL_LSR_OE | -- cgit v0.10.2 From 79f203a26a07a9d5701c404925e85eb161b72cde Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Thu, 5 Aug 2010 17:01:07 -0400 Subject: USB: ssu100: remove duplicate #defines in ssu100 The ssu100 uses a TI16C550C UART so the SERIAL_ defines in this code are duplicates of those found in serial_reg.h. Remove the defines in ssu100.c and use the ones in the header file. Signed-off-by: Bill Pemberton Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index c719388..3c586b5 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #define QT_OPEN_CLOSE_CHANNEL 0xca @@ -27,36 +28,11 @@ #define QT_HW_FLOW_CONTROL_MASK 0xc5 #define QT_SW_FLOW_CONTROL_MASK 0xc6 -#define MODEM_CTL_REGISTER 0x04 -#define MODEM_STATUS_REGISTER 0x06 - - -#define SERIAL_LSR_OE 0x02 -#define SERIAL_LSR_PE 0x04 -#define SERIAL_LSR_FE 0x08 -#define SERIAL_LSR_BI 0x10 - -#define SERIAL_LSR_TEMT 0x40 - -#define SERIAL_MCR_DTR 0x01 -#define SERIAL_MCR_RTS 0x02 -#define SERIAL_MCR_LOOP 0x10 - -#define SERIAL_MSR_CTS 0x10 -#define SERIAL_MSR_CD 0x80 -#define SERIAL_MSR_RI 0x40 -#define SERIAL_MSR_DSR 0x20 #define SERIAL_MSR_MASK 0xf0 -#define SERIAL_CRTSCTS ((SERIAL_MCR_RTS << 8) | SERIAL_MSR_CTS) - -#define SERIAL_8_DATA 0x03 -#define SERIAL_7_DATA 0x02 -#define SERIAL_6_DATA 0x01 -#define SERIAL_5_DATA 0x00 +#define SERIAL_CRTSCTS ((UART_MCR_RTS << 8) | UART_MSR_CTS) -#define SERIAL_ODD_PARITY 0X08 -#define SERIAL_EVEN_PARITY 0X18 +#define SERIAL_EVEN_PARITY (UART_LCR_PARITY | UART_LCR_EPAR) #define MAX_BAUD_RATE 460800 @@ -153,7 +129,7 @@ static inline int ssu100_setregister(struct usb_device *dev, unsigned short uart, u16 data) { - u16 value = (data << 8) | MODEM_CTL_REGISTER; + u16 value = (data << 8) | UART_MCR; return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), QT_SET_GET_REGISTER, 0x40, value, uart, @@ -179,9 +155,9 @@ static inline int update_mctrl(struct usb_device *dev, unsigned int set, clear &= ~set; /* 'set' takes precedence over 'clear' */ urb_value = 0; if (set & TIOCM_DTR) - urb_value |= SERIAL_MCR_DTR; + urb_value |= UART_MCR_DTR; if (set & TIOCM_RTS) - urb_value |= SERIAL_MCR_RTS; + urb_value |= UART_MCR_RTS; result = ssu100_setregister(dev, 0, urb_value); if (result < 0) @@ -265,24 +241,24 @@ static void ssu100_set_termios(struct tty_struct *tty, if (cflag & PARENB) { if (cflag & PARODD) - urb_value |= SERIAL_ODD_PARITY; + urb_value |= UART_LCR_PARITY; else urb_value |= SERIAL_EVEN_PARITY; } switch (cflag & CSIZE) { case CS5: - urb_value |= SERIAL_5_DATA; + urb_value |= UART_LCR_WLEN5; break; case CS6: - urb_value |= SERIAL_6_DATA; + urb_value |= UART_LCR_WLEN6; break; case CS7: - urb_value |= SERIAL_7_DATA; + urb_value |= UART_LCR_WLEN7; break; default: case CS8: - urb_value |= SERIAL_8_DATA; + urb_value |= UART_LCR_WLEN8; break; } @@ -353,11 +329,11 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) } spin_lock_irqsave(&priv->status_lock, flags); - priv->shadowLSR = data[0] & (SERIAL_LSR_OE | SERIAL_LSR_PE | - SERIAL_LSR_FE | SERIAL_LSR_BI); + priv->shadowLSR = data[0] & (UART_LSR_OE | UART_LSR_PE | + UART_LSR_FE | UART_LSR_BI); - priv->shadowMSR = data[1] & (SERIAL_MSR_CTS | SERIAL_MSR_DSR | - SERIAL_MSR_RI | SERIAL_MSR_CD); + priv->shadowMSR = data[1] & (UART_MSR_CTS | UART_MSR_DSR | + UART_MSR_RI | UART_MSR_DCD); spin_unlock_irqrestore(&priv->status_lock, flags); kfree(data); @@ -430,10 +406,10 @@ static int ssu100_ioctl(struct tty_struct *tty, struct file *file, /* Return 0 if caller wanted to know about these bits */ - if (((arg & TIOCM_RNG) && (diff & SERIAL_MSR_RI)) || - ((arg & TIOCM_DSR) && (diff & SERIAL_MSR_DSR)) || - ((arg & TIOCM_CD) && (diff & SERIAL_MSR_CD)) || - ((arg & TIOCM_CTS) && (diff & SERIAL_MSR_CTS))) + if (((arg & TIOCM_RNG) && (diff & UART_MSR_RI)) || + ((arg & TIOCM_DSR) && (diff & UART_MSR_DSR)) || + ((arg & TIOCM_CD) && (diff & UART_MSR_DCD)) || + ((arg & TIOCM_CTS) && (diff & UART_MSR_CTS))) return 0; } } @@ -513,20 +489,20 @@ static int ssu100_tiocmget(struct tty_struct *tty, struct file *file) if (!d) return -ENOMEM; - r = ssu100_getregister(dev, 0, MODEM_CTL_REGISTER, d); + r = ssu100_getregister(dev, 0, UART_MCR, d); if (r < 0) goto mget_out; - r = ssu100_getregister(dev, 0, MODEM_STATUS_REGISTER, d+1); + r = ssu100_getregister(dev, 0, UART_MSR, d+1); if (r < 0) goto mget_out; - r = (d[0] & SERIAL_MCR_DTR ? TIOCM_DTR : 0) | - (d[0] & SERIAL_MCR_RTS ? TIOCM_RTS : 0) | - (d[1] & SERIAL_MSR_CTS ? TIOCM_CTS : 0) | - (d[1] & SERIAL_MSR_CD ? TIOCM_CAR : 0) | - (d[1] & SERIAL_MSR_RI ? TIOCM_RI : 0) | - (d[1] & SERIAL_MSR_DSR ? TIOCM_DSR : 0); + r = (d[0] & UART_MCR_DTR ? TIOCM_DTR : 0) | + (d[0] & UART_MCR_RTS ? TIOCM_RTS : 0) | + (d[1] & UART_MSR_CTS ? TIOCM_CTS : 0) | + (d[1] & UART_MSR_DCD ? TIOCM_CAR : 0) | + (d[1] & UART_MSR_RI ? TIOCM_RI : 0) | + (d[1] & UART_MSR_DSR ? TIOCM_DSR : 0); mget_out: kfree(d); @@ -579,10 +555,10 @@ static int ssu100_process_packet(struct tty_struct *tty, (packet[0] == 0x1b) && (packet[1] == 0x1b) && ((packet[2] == 0x00) || (packet[2] == 0x01))) { if (packet[2] == 0x00) - priv->shadowLSR = packet[3] & (SERIAL_LSR_OE | - SERIAL_LSR_PE | - SERIAL_LSR_FE | - SERIAL_LSR_BI); + priv->shadowLSR = packet[3] & (UART_LSR_OE | + UART_LSR_PE | + UART_LSR_FE | + UART_LSR_BI); if (packet[2] == 0x01) { priv->shadowMSR = packet[3]; -- cgit v0.10.2 From 556f1a0e9c178193e584209b47cf1cb9f669bd51 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Thu, 5 Aug 2010 17:01:08 -0400 Subject: USB: ssu100: add register parameter to ssu100_setregister The function ssu100_setregister was hard coded to only set the MCR register. Add a register parameter so that other registers can be set. Signed-off-by: Bill Pemberton Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 3c586b5..ad5f9ae 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -127,9 +127,10 @@ static inline int ssu100_getregister(struct usb_device *dev, static inline int ssu100_setregister(struct usb_device *dev, unsigned short uart, + unsigned short reg, u16 data) { - u16 value = (data << 8) | UART_MCR; + u16 value = (data << 8) | reg; return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), QT_SET_GET_REGISTER, 0x40, value, uart, @@ -159,7 +160,7 @@ static inline int update_mctrl(struct usb_device *dev, unsigned int set, if (set & TIOCM_RTS) urb_value |= UART_MCR_RTS; - result = ssu100_setregister(dev, 0, urb_value); + result = ssu100_setregister(dev, 0, UART_MCR, urb_value); if (result < 0) dbg("%s Error from MODEM_CTRL urb", __func__); @@ -529,7 +530,7 @@ static void ssu100_dtr_rts(struct usb_serial_port *port, int on) if (!port->serial->disconnected) { /* Disable flow control */ if (!on && - ssu100_setregister(dev, 0, 0) < 0) + ssu100_setregister(dev, 0, UART_MCR, 0) < 0) dev_err(&port->dev, "error from flowcontrol urb\n"); /* drop RTS and DTR */ if (on) -- cgit v0.10.2 From f81c83db563334d8377b26ad45585261f604605a Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Thu, 5 Aug 2010 17:01:09 -0400 Subject: USB: ssu100: rework logic for TIOCMIWAIT Rework the logic for TIOCMIWAIT to use wait_event_interruptible. This also adds support for TIOCGICOUNT. Signed-off-by: Bill Pemberton Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index ad5f9ae..e244491 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -80,6 +80,7 @@ struct ssu100_port_private { u8 shadowMSR; wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ unsigned short max_packet_size; + struct async_icount icount; }; static void ssu100_release(struct usb_serial *serial) @@ -330,11 +331,8 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) } spin_lock_irqsave(&priv->status_lock, flags); - priv->shadowLSR = data[0] & (UART_LSR_OE | UART_LSR_PE | - UART_LSR_FE | UART_LSR_BI); - - priv->shadowMSR = data[1] & (UART_MSR_CTS | UART_MSR_DSR | - UART_MSR_RI | UART_MSR_DCD); + priv->shadowLSR = data[0]; + priv->shadowMSR = data[1]; spin_unlock_irqrestore(&priv->status_lock, flags); kfree(data); @@ -379,11 +377,51 @@ static int get_serial_info(struct usb_serial_port *port, return 0; } +static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) +{ + struct ssu100_port_private *priv = usb_get_serial_port_data(port); + struct async_icount prev, cur; + unsigned long flags; + + spin_lock_irqsave(&priv->status_lock, flags); + prev = priv->icount; + spin_unlock_irqrestore(&priv->status_lock, flags); + + while (1) { + wait_event_interruptible(priv->delta_msr_wait, + ((priv->icount.rng != prev.rng) || + (priv->icount.dsr != prev.dsr) || + (priv->icount.dcd != prev.dcd) || + (priv->icount.cts != prev.cts))); + + if (signal_pending(current)) + return -ERESTARTSYS; + + spin_lock_irqsave(&priv->status_lock, flags); + cur = priv->icount; + spin_unlock_irqrestore(&priv->status_lock, flags); + + if ((prev.rng == cur.rng) && + (prev.dsr == cur.dsr) && + (prev.dcd == cur.dcd) && + (prev.cts == cur.cts)) + return -EIO; + + if ((arg & TIOCM_RNG && (prev.rng != cur.rng)) || + (arg & TIOCM_DSR && (prev.dsr != cur.dsr)) || + (arg & TIOCM_CD && (prev.dcd != cur.dcd)) || + (arg & TIOCM_CTS && (prev.cts != cur.cts))) + return 0; + } + return 0; +} + static int ssu100_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; struct ssu100_port_private *priv = usb_get_serial_port_data(port); + void __user *user_arg = (void __user *)arg; dbg("%s cmd 0x%04x", __func__, cmd); @@ -393,28 +431,28 @@ static int ssu100_ioctl(struct tty_struct *tty, struct file *file, (struct serial_struct __user *) arg); case TIOCMIWAIT: - while (priv != NULL) { - u8 prevMSR = priv->shadowMSR & SERIAL_MSR_MASK; - interruptible_sleep_on(&priv->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - else { - u8 diff = (priv->shadowMSR & SERIAL_MSR_MASK) ^ prevMSR; - if (!diff) - return -EIO; /* no change => error */ - - /* Return 0 if caller wanted to know about - these bits */ - - if (((arg & TIOCM_RNG) && (diff & UART_MSR_RI)) || - ((arg & TIOCM_DSR) && (diff & UART_MSR_DSR)) || - ((arg & TIOCM_CD) && (diff & UART_MSR_DCD)) || - ((arg & TIOCM_CTS) && (diff & UART_MSR_CTS))) - return 0; - } - } + return wait_modem_info(port, arg); + + case TIOCGICOUNT: + { + struct serial_icounter_struct icount; + struct async_icount cnow = priv->icount; + memset(&icount, 0, sizeof(icount)); + icount.cts = cnow.cts; + icount.dsr = cnow.dsr; + icount.rng = cnow.rng; + icount.dcd = cnow.dcd; + icount.rx = cnow.rx; + icount.tx = cnow.tx; + icount.frame = cnow.frame; + icount.overrun = cnow.overrun; + icount.parity = cnow.parity; + icount.brk = cnow.brk; + icount.buf_overrun = cnow.buf_overrun; + if (copy_to_user(user_arg, &icount, sizeof(icount))) + return -EFAULT; return 0; + } default: break; @@ -541,6 +579,50 @@ static void ssu100_dtr_rts(struct usb_serial_port *port, int on) mutex_unlock(&port->serial->disc_mutex); } +static void ssu100_update_msr(struct usb_serial_port *port, u8 msr) +{ + struct ssu100_port_private *priv = usb_get_serial_port_data(port); + unsigned long flags; + + spin_lock_irqsave(&priv->status_lock, flags); + priv->shadowMSR = msr; + spin_unlock_irqrestore(&priv->status_lock, flags); + + if (msr & UART_MSR_ANY_DELTA) { + /* update input line counters */ + if (msr & UART_MSR_DCTS) + priv->icount.cts++; + if (msr & UART_MSR_DDSR) + priv->icount.dsr++; + if (msr & UART_MSR_DDCD) + priv->icount.dcd++; + if (msr & UART_MSR_TERI) + priv->icount.rng++; + wake_up_interruptible(&priv->delta_msr_wait); + } +} + +static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr) +{ + struct ssu100_port_private *priv = usb_get_serial_port_data(port); + unsigned long flags; + + spin_lock_irqsave(&priv->status_lock, flags); + priv->shadowLSR = lsr; + spin_unlock_irqrestore(&priv->status_lock, flags); + + if (lsr & UART_LSR_BRK_ERROR_BITS) { + if (lsr & UART_LSR_BI) + priv->icount.brk++; + if (lsr & UART_LSR_FE) + priv->icount.frame++; + if (lsr & UART_LSR_PE) + priv->icount.parity++; + if (lsr & UART_LSR_OE) + priv->icount.overrun++; + } +} + static int ssu100_process_packet(struct tty_struct *tty, struct usb_serial_port *port, struct ssu100_port_private *priv, @@ -556,15 +638,9 @@ static int ssu100_process_packet(struct tty_struct *tty, (packet[0] == 0x1b) && (packet[1] == 0x1b) && ((packet[2] == 0x00) || (packet[2] == 0x01))) { if (packet[2] == 0x00) - priv->shadowLSR = packet[3] & (UART_LSR_OE | - UART_LSR_PE | - UART_LSR_FE | - UART_LSR_BI); - - if (packet[2] == 0x01) { - priv->shadowMSR = packet[3]; - wake_up_interruptible(&priv->delta_msr_wait); - } + ssu100_update_lsr(port, packet[3]); + if (packet[2] == 0x01) + ssu100_update_msr(port, packet[3]); len -= 4; ch = packet + 4; -- cgit v0.10.2 From 5c7efeb76e7dc5145b467657fa049f3c1bd9cf58 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Thu, 5 Aug 2010 17:01:10 -0400 Subject: USB: serial: export symbol usb_serial_generic_disconnect This is needed by the ssu100 driver to use this function. Signed-off-by: Bill Pemberton Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index ca92f67..0b1a133 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -518,6 +518,7 @@ void usb_serial_generic_disconnect(struct usb_serial *serial) for (i = 0; i < serial->num_ports; ++i) generic_cleanup(serial->port[i]); } +EXPORT_SYMBOL_GPL(usb_serial_generic_disconnect); void usb_serial_generic_release(struct usb_serial *serial) { -- cgit v0.10.2 From 85dee135b84f1c7cad252fa4a619ea692077a7fc Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Thu, 5 Aug 2010 17:01:11 -0400 Subject: USB: ssu100: add disconnect function for ssu100 Add a disconnect function to the functions of this device. The disconnect is a call to usb_serial_generic_disconnect() so it requires that symbol to be exported from generic.c. Signed-off-by: Bill Pemberton Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index e244491..55e9672 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -687,7 +687,6 @@ static void ssu100_process_read_urb(struct urb *urb) tty_kref_put(tty); } - static struct usb_serial_driver ssu100_device = { .driver = { .owner = THIS_MODULE, @@ -709,6 +708,7 @@ static struct usb_serial_driver ssu100_device = { .tiocmset = ssu100_tiocmset, .ioctl = ssu100_ioctl, .set_termios = ssu100_set_termios, + .disconnect = usb_serial_generic_disconnect, }; static int __init ssu100_init(void) -- cgit v0.10.2 From 6b8f1ca5581bf9783069cd6bde65ba7a3a470aab Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Fri, 13 Aug 2010 09:59:31 -0400 Subject: USB: ssu100: set tty_flags in ssu100_process_packet flag was never set in ssu100_process_packet. Add logic to set it before calling tty_insert_flip_* Signed-off-by: Bill Pemberton Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 55e9672..660c31f 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -602,7 +602,8 @@ static void ssu100_update_msr(struct usb_serial_port *port, u8 msr) } } -static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr) +static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr, + char *tty_flag) { struct ssu100_port_private *priv = usb_get_serial_port_data(port); unsigned long flags; @@ -611,16 +612,32 @@ static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr) priv->shadowLSR = lsr; spin_unlock_irqrestore(&priv->status_lock, flags); + *tty_flag = TTY_NORMAL; if (lsr & UART_LSR_BRK_ERROR_BITS) { - if (lsr & UART_LSR_BI) + /* we always want to update icount, but we only want to + * update tty_flag for one case */ + if (lsr & UART_LSR_BI) { priv->icount.brk++; - if (lsr & UART_LSR_FE) - priv->icount.frame++; - if (lsr & UART_LSR_PE) + *tty_flag = TTY_BREAK; + usb_serial_handle_break(port); + } + if (lsr & UART_LSR_PE) { priv->icount.parity++; - if (lsr & UART_LSR_OE) + if (*tty_flag == TTY_NORMAL) + *tty_flag = TTY_PARITY; + } + if (lsr & UART_LSR_FE) { + priv->icount.frame++; + if (*tty_flag == TTY_NORMAL) + *tty_flag = TTY_FRAME; + } + if (lsr & UART_LSR_OE){ priv->icount.overrun++; + if (*tty_flag == TTY_NORMAL) + *tty_flag = TTY_OVERRUN; + } } + } static int ssu100_process_packet(struct tty_struct *tty, @@ -629,7 +646,7 @@ static int ssu100_process_packet(struct tty_struct *tty, char *packet, int len) { int i; - char flag; + char flag = TTY_NORMAL; char *ch; dbg("%s - port %d", __func__, port->number); @@ -637,8 +654,11 @@ static int ssu100_process_packet(struct tty_struct *tty, if ((len >= 4) && (packet[0] == 0x1b) && (packet[1] == 0x1b) && ((packet[2] == 0x00) || (packet[2] == 0x01))) { - if (packet[2] == 0x00) - ssu100_update_lsr(port, packet[3]); + if (packet[2] == 0x00) { + ssu100_update_lsr(port, packet[3], &flag); + if (flag == TTY_OVERRUN) + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + } if (packet[2] == 0x01) ssu100_update_msr(port, packet[3]); -- cgit v0.10.2 From d187abb9a83e6c6b6e9f2ca17962bdeafb4bc903 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 11 Aug 2010 12:07:13 -0700 Subject: USB: gadget: fix composite kernel-doc warnings Warning(include/linux/usb/composite.h:284): No description found for parameter 'disconnect' Warning(drivers/usb/gadget/composite.c:744): No description found for parameter 'c' Warning(drivers/usb/gadget/composite.c:744): Excess function parameter 'cdev' description in 'usb_string_ids_n' Signed-off-by: Randy Dunlap Cc: David Brownell Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index e483f80..1160c55 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -723,12 +723,12 @@ int usb_string_ids_tab(struct usb_composite_dev *cdev, struct usb_string *str) /** * usb_string_ids_n() - allocate unused string IDs in batch - * @cdev: the device whose string descriptor IDs are being allocated + * @c: the device whose string descriptor IDs are being allocated * @n: number of string IDs to allocate * Context: single threaded during gadget setup * * Returns the first requested ID. This ID and next @n-1 IDs are now - * valid IDs. At least providind that @n is non zore because if it + * valid IDs. At least provided that @n is non-zero because if it * is, returns last requested ID which is now very useful information. * * @usb_string_ids_n() is called from bind() callbacks to allocate diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 890bc14..6170681 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -247,6 +247,7 @@ int usb_add_config(struct usb_composite_dev *, * value; it should return zero on successful initialization. * @unbind: Reverses @bind(); called as a side effect of unregistering * this driver. + * @disconnect: optional driver disconnect method * @suspend: Notifies when the host stops sending USB traffic, * after function notifications * @resume: Notifies configuration when the host restarts USB traffic, -- cgit v0.10.2 From 7c81aafaf059b81ead2330bc13db78269ef62612 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 11 Aug 2010 12:10:48 +0200 Subject: USB: gadget: Return -ENOMEM on memory allocation failure In this code, 0 is returned on memory allocation failure, even though other failures return -ENOMEM or other similar values. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression ret; expression x,e1,e2,e3; @@ ret = 0 ... when != ret = e1 *x = \(kmalloc\|kcalloc\|kzalloc\)(...) ... when != ret = e2 if (x == NULL) { ... when != ret = e3 return ret; } // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 166bf71..e03058f 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1609,6 +1609,7 @@ static int __init m66592_probe(struct platform_device *pdev) /* initialize ucd */ m66592 = kzalloc(sizeof(struct m66592), GFP_KERNEL); if (m66592 == NULL) { + ret = -ENOMEM; pr_err("kzalloc error\n"); goto clean_up; } -- cgit v0.10.2 From 461c317705eca5cac09a360f488715927fd0a927 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 11 Aug 2010 13:02:32 +0300 Subject: USB: otg: twl4030: fix wrong assumption of starting state The reset state of twl4030-usb is not sleeping, it starts up awaken and we need to disable it if we have booted with a disconnected cable to avoid over consumption on the default state. To avoid problems later, we read the current state of the transceiver from the PHY_PWR_CTRL register. The bootloader can, anyways, put the device to sleep before us. Tested on a custom OMAP board. Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c index 0e88885..05aaac1 100644 --- a/drivers/usb/otg/twl4030-usb.c +++ b/drivers/usb/otg/twl4030-usb.c @@ -550,6 +550,7 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev) struct twl4030_usb_data *pdata = pdev->dev.platform_data; struct twl4030_usb *twl; int status, err; + u8 pwr; if (!pdata) { dev_dbg(&pdev->dev, "platform_data not available\n"); @@ -568,7 +569,10 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev) twl->otg.set_peripheral = twl4030_set_peripheral; twl->otg.set_suspend = twl4030_set_suspend; twl->usb_mode = pdata->usb_mode; - twl->asleep = 1; + + pwr = twl4030_usb_read(twl, PHY_PWR_CTRL); + + twl->asleep = (pwr & PHY_PWR_PHYPWD); /* init spinlock for workqueue */ spin_lock_init(&twl->lock); -- cgit v0.10.2 From fd6e5bbb241720715cee737f534496d7c0ae9022 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Tue, 10 Aug 2010 14:29:19 -0700 Subject: USB: serial: io_ti.c: don't return 0 if writing the download record failed If the write download record failed we shouldn't return 0. Signed-off-by: Roel Kluin Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index c3f27c3..a7cfc59 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -1284,7 +1284,7 @@ static int download_fw(struct edgeport_serial *serial) kfree(header); kfree(rom_desc); kfree(ti_manuf_desc); - return status; + return -EINVAL; } /* Update I2C with type 0xf2 record with correct -- cgit v0.10.2 From 666cc076d284e32d11bfc5ea2fbfc50434cff051 Mon Sep 17 00:00:00 2001 From: Martin Michlmayr Date: Tue, 10 Aug 2010 20:31:21 +0100 Subject: USB: ftdi_sio: Add ID for Ionics PlugComputer Add the ID for the Ionics PlugComputer (). Signed-off-by: Martin Michlmayr Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index e04a416..aeb9331 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -750,6 +750,8 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH4_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(FTDI_VID, SEGWAY_RMP200_PID) }, + { USB_DEVICE(IONICS_VID, IONICS_PLUGCOMPUTER_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 6e612c5..aa37cc5 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -989,6 +989,12 @@ #define ALTI2_N3_PID 0x6001 /* Neptune 3 */ /* + * Ionics PlugComputer + */ +#define IONICS_VID 0x1c0c +#define IONICS_PLUGCOMPUTER_PID 0x0102 + +/* * Dresden Elektronik Sensor Terminal Board */ #define DE_VID 0x1cf1 /* Vendor ID */ -- cgit v0.10.2 From a1669b2c64a9c8b031e0ac5cbf2692337a577f7c Mon Sep 17 00:00:00 2001 From: John Youn Date: Mon, 9 Aug 2010 13:56:11 -0700 Subject: USB: xhci: Remove buggy assignment in next_trb() The code to increment the TRB pointer has a slight ambiguity that could lead to a bug on different compilers. The ANSI C specification does not specify the precedence of the assignment operator over the postfix operator. gcc 4.4 produced the correct code (increment the pointer and assign the value), but a MIPS compiler that one of John's clients used assigned the old (unincremented) value. Remove the unnecessary assignment to make all compilers produce the correct assembly. Signed-off-by: John Youn Signed-off-by: Sarah Sharp Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index bc3f4f4..2f19f3a 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -131,7 +131,7 @@ static void next_trb(struct xhci_hcd *xhci, *seg = (*seg)->next; *trb = ((*seg)->trbs); } else { - *trb = (*trb)++; + (*trb)++; } } -- cgit v0.10.2 From 14184f9b8047026f1812f49df074e89dad3a09bc Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Mon, 9 Aug 2010 13:56:15 -0700 Subject: USB: xHCI: update ring dequeue pointer when process missed tds This patch fixes a isoc transfer bug reported by Sander Eikelenboom. When ep->skip is set, endpoint ring dequeue pointer should be updated when processed every missed td. Although ring dequeue pointer will also be updated when ep->skip is clear, leave it intact during missed tds processing may cause two issues: 1). If the very next valid transfer following missed tds is a short transfer, its actual_length will be miscalculated; 2). If there are too many missed tds during transfer, new inserted tds may found the transfer ring full and urb enqueue fails. Reported-by: Sander Eikelenboom Tested-by: Sander Eikelenboom Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 2f19f3a..48e60d1 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1551,6 +1551,10 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, /* calc actual length */ if (ep->skip) { td->urb->iso_frame_desc[idx].actual_length = 0; + /* Update ring dequeue pointer */ + while (ep_ring->dequeue != td->last_trb) + inc_deq(xhci, ep_ring, false); + inc_deq(xhci, ep_ring, false); return finish_td(xhci, td, event_trb, event, ep, status, true); } -- cgit v0.10.2 From 6d4d4554863b7897f2bc9cd9085f54c819152825 Mon Sep 17 00:00:00 2001 From: Kulikov Vasiliy Date: Sat, 31 Jul 2010 21:39:46 +0400 Subject: USB: iowarrior: fix misuse of return value of copy_to_user() copy_to_user() returns number of not copied bytes, not error code. Signed-off-by: Kulikov Vasiliy Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index 2de49c8..bc88c79 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -542,7 +542,7 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd, retval = io_res; else { io_res = copy_to_user(user_buffer, buffer, dev->report_size); - if (io_res < 0) + if (io_res) retval = -EFAULT; } break; @@ -574,7 +574,7 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd, } io_res = copy_to_user((struct iowarrior_info __user *)arg, &info, sizeof(struct iowarrior_info)); - if (io_res < 0) + if (io_res) retval = -EFAULT; break; } -- cgit v0.10.2 From 1865a9c382ede507065cf1575308b53495814c7d Mon Sep 17 00:00:00 2001 From: Kulikov Vasiliy Date: Sat, 31 Jul 2010 21:40:07 +0400 Subject: USB: adutux: fix misuse of return value of copy_to_user() copy_to_user() returns number of not copied bytes, not error code. Signed-off-by: Kulikov Vasiliy Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index d240de0..801324a 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -439,7 +439,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count, /* drain secondary buffer */ int amount = bytes_to_read < data_in_secondary ? bytes_to_read : data_in_secondary; i = copy_to_user(buffer, dev->read_buffer_secondary+dev->secondary_head, amount); - if (i < 0) { + if (i) { retval = -EFAULT; goto exit; } -- cgit v0.10.2 From ea233f805537f5da16c2b34d85b6c5cf88a0f9aa Mon Sep 17 00:00:00 2001 From: Galen Seitz Date: Thu, 19 Aug 2010 11:15:20 -0700 Subject: USB: ftdi_sio: add product ID for Lenz LI-USB Add ftdi product ID for Lenz LI-USB, a model train interface. This was NOT tested against 2.6.35, but a similar patch was tested with the CentOS 2.6.18-194.11.1.el5 kernel. It wasn't clear to me what ordering is being used in ftdi_sio.c, so I inserted the ID after another model train entry(SPROG_II). Signed-off-by: Galen Seitz Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index aeb9331..63ddb2f 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -180,6 +180,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SPROG_II) }, + { USB_DEVICE(FTDI_VID, FTDI_LENZ_LIUSB_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_547_PID) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index aa37cc5..2e95857 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -110,6 +110,9 @@ /* Propox devices */ #define FTDI_PROPOX_JTAGCABLEII_PID 0xD738 +/* Lenz LI-USB Computer Interface. */ +#define FTDI_LENZ_LIUSB_PID 0xD780 + /* * Xsens Technologies BV products (http://www.xsens.com). */ -- cgit v0.10.2 From 70ddd47f7d56f17b40f78d21d6f653c84617e450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 13 Aug 2010 14:06:50 +0200 Subject: ARM: imx: fix build failure concerning otg/ulpi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The build failure was introduced by 13dd0c9 (USB: otg/ulpi: extend the generic ulpi driver.) Signed-off-by: Uwe Kleine-König Acked-by: Igor Grinberg Cc: Mike Rapoport Signed-off-by: Greg Kroah-Hartman diff --git a/arch/arm/mach-imx/mach-cpuimx27.c b/arch/arm/mach-imx/mach-cpuimx27.c index 575ff1a..339150a 100644 --- a/arch/arm/mach-imx/mach-cpuimx27.c +++ b/arch/arm/mach-imx/mach-cpuimx27.c @@ -279,13 +279,13 @@ static void __init eukrea_cpuimx27_init(void) #if defined(CONFIG_USB_ULPI) if (otg_mode_host) { otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); + ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT); mxc_register_device(&mxc_otg_host, &otg_pdata); } usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); + ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT); mxc_register_device(&mxc_usbh2, &usbh2_pdata); #endif diff --git a/arch/arm/mach-imx/mach-pca100.c b/arch/arm/mach-imx/mach-pca100.c index a389d11..23c9e1f 100644 --- a/arch/arm/mach-imx/mach-pca100.c +++ b/arch/arm/mach-imx/mach-pca100.c @@ -419,13 +419,13 @@ static void __init pca100_init(void) #if defined(CONFIG_USB_ULPI) if (otg_mode_host) { otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); + ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT); mxc_register_device(&mxc_otg_host, &otg_pdata); } usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); + ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT); mxc_register_device(&mxc_usbh2, &usbh2_pdata); #endif diff --git a/arch/arm/mach-mx25/mach-cpuimx25.c b/arch/arm/mach-mx25/mach-cpuimx25.c index 56b2e26..a5f0174 100644 --- a/arch/arm/mach-mx25/mach-cpuimx25.c +++ b/arch/arm/mach-mx25/mach-cpuimx25.c @@ -138,7 +138,7 @@ static void __init eukrea_cpuimx25_init(void) #if defined(CONFIG_USB_ULPI) if (otg_mode_host) { otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); + ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT); mxc_register_device(&mxc_otg, &otg_pdata); } diff --git a/arch/arm/mach-mx3/mach-cpuimx35.c b/arch/arm/mach-mx3/mach-cpuimx35.c index 63f970f..9770a6a 100644 --- a/arch/arm/mach-mx3/mach-cpuimx35.c +++ b/arch/arm/mach-mx3/mach-cpuimx35.c @@ -192,7 +192,7 @@ static void __init mxc_board_init(void) #if defined(CONFIG_USB_ULPI) if (otg_mode_host) { otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); + ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT); mxc_register_device(&mxc_otg_host, &otg_pdata); } -- cgit v0.10.2 From 529b7307d804f649839b5b65b303442140266d26 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 24 Aug 2010 14:41:48 +1000 Subject: powerpc: Make rwsem use "long" type This makes the 64-bit kernel use 64-bit signed integers for the counter (effectively supporting 32-bit of active count in the semaphore), thus avoiding things like overflow of the mmap_sem if you use a really crazy number of threads Note: Ideally the type in the structure should be atomic_long_t rather than "long". However, there's some nasty issues with that. It needs to be initialized statically -and- lib/rwsem.c does things like sem->count = RWSEM_UNLOCKED_VALUE; Now, if you mix in the fact that atomic_* types are actually structures with one member and note typedefs of a scalar, it makes its really nasty. So I stuck to what we did before using a long and casts for now. Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/rwsem.h b/arch/powerpc/include/asm/rwsem.h index 24cd928..8447d89 100644 --- a/arch/powerpc/include/asm/rwsem.h +++ b/arch/powerpc/include/asm/rwsem.h @@ -21,15 +21,20 @@ /* * the semaphore definition */ -struct rw_semaphore { - /* XXX this should be able to be an atomic_t -- paulus */ - signed int count; -#define RWSEM_UNLOCKED_VALUE 0x00000000 -#define RWSEM_ACTIVE_BIAS 0x00000001 -#define RWSEM_ACTIVE_MASK 0x0000ffff -#define RWSEM_WAITING_BIAS (-0x00010000) +#ifdef CONFIG_PPC64 +# define RWSEM_ACTIVE_MASK 0xffffffffL +#else +# define RWSEM_ACTIVE_MASK 0x0000ffffL +#endif + +#define RWSEM_UNLOCKED_VALUE 0x00000000L +#define RWSEM_ACTIVE_BIAS 0x00000001L +#define RWSEM_WAITING_BIAS (-RWSEM_ACTIVE_MASK-1) #define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS #define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) + +struct rw_semaphore { + long count; spinlock_t wait_lock; struct list_head wait_list; #ifdef CONFIG_DEBUG_LOCK_ALLOC @@ -43,9 +48,13 @@ struct rw_semaphore { # define __RWSEM_DEP_MAP_INIT(lockname) #endif -#define __RWSEM_INITIALIZER(name) \ - { RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait_lock), \ - LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) } +#define __RWSEM_INITIALIZER(name) \ +{ \ + RWSEM_UNLOCKED_VALUE, \ + __SPIN_LOCK_UNLOCKED((name).wait_lock), \ + LIST_HEAD_INIT((name).wait_list) \ + __RWSEM_DEP_MAP_INIT(name) \ +} #define DECLARE_RWSEM(name) \ struct rw_semaphore name = __RWSEM_INITIALIZER(name) @@ -70,13 +79,13 @@ extern void __init_rwsem(struct rw_semaphore *sem, const char *name, */ static inline void __down_read(struct rw_semaphore *sem) { - if (unlikely(atomic_inc_return((atomic_t *)(&sem->count)) <= 0)) + if (unlikely(atomic_long_inc_return((atomic_long_t *)&sem->count) <= 0)) rwsem_down_read_failed(sem); } static inline int __down_read_trylock(struct rw_semaphore *sem) { - int tmp; + long tmp; while ((tmp = sem->count) >= 0) { if (tmp == cmpxchg(&sem->count, tmp, @@ -92,10 +101,10 @@ static inline int __down_read_trylock(struct rw_semaphore *sem) */ static inline void __down_write_nested(struct rw_semaphore *sem, int subclass) { - int tmp; + long tmp; - tmp = atomic_add_return(RWSEM_ACTIVE_WRITE_BIAS, - (atomic_t *)(&sem->count)); + tmp = atomic_long_add_return(RWSEM_ACTIVE_WRITE_BIAS, + (atomic_long_t *)&sem->count); if (unlikely(tmp != RWSEM_ACTIVE_WRITE_BIAS)) rwsem_down_write_failed(sem); } @@ -107,7 +116,7 @@ static inline void __down_write(struct rw_semaphore *sem) static inline int __down_write_trylock(struct rw_semaphore *sem) { - int tmp; + long tmp; tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE, RWSEM_ACTIVE_WRITE_BIAS); @@ -119,9 +128,9 @@ static inline int __down_write_trylock(struct rw_semaphore *sem) */ static inline void __up_read(struct rw_semaphore *sem) { - int tmp; + long tmp; - tmp = atomic_dec_return((atomic_t *)(&sem->count)); + tmp = atomic_long_dec_return((atomic_long_t *)&sem->count); if (unlikely(tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0)) rwsem_wake(sem); } @@ -131,17 +140,17 @@ static inline void __up_read(struct rw_semaphore *sem) */ static inline void __up_write(struct rw_semaphore *sem) { - if (unlikely(atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS, - (atomic_t *)(&sem->count)) < 0)) + if (unlikely(atomic_long_sub_return(RWSEM_ACTIVE_WRITE_BIAS, + (atomic_long_t *)&sem->count) < 0)) rwsem_wake(sem); } /* * implement atomic add functionality */ -static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem) +static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem) { - atomic_add(delta, (atomic_t *)(&sem->count)); + atomic_long_add(delta, (atomic_long_t *)&sem->count); } /* @@ -149,9 +158,10 @@ static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem) */ static inline void __downgrade_write(struct rw_semaphore *sem) { - int tmp; + long tmp; - tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count)); + tmp = atomic_long_add_return(-RWSEM_WAITING_BIAS, + (atomic_long_t *)&sem->count); if (tmp < 0) rwsem_downgrade_wake(sem); } @@ -159,14 +169,14 @@ static inline void __downgrade_write(struct rw_semaphore *sem) /* * implement exchange and add functionality */ -static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem) +static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem) { - return atomic_add_return(delta, (atomic_t *)(&sem->count)); + return atomic_long_add_return(delta, (atomic_long_t *)&sem->count); } static inline int rwsem_is_locked(struct rw_semaphore *sem) { - return (sem->count != 0); + return sem->count != 0; } #endif /* __KERNEL__ */ -- cgit v0.10.2 From 79c3095fb39964d0d44368cbbb4eff5b52c43d2c Mon Sep 17 00:00:00 2001 From: Sonny Rao Date: Thu, 19 Aug 2010 18:08:09 +0000 Subject: powerpc: Export memstart_addr and kernstart_addr on ppc64 Some modules (like eHCA) want to map all of kernel memory, for this to work with a relocated kernel, we need to export kernstart_addr so modules can use PHYSICAL_START and memstart_addr so they could use MEMORY_START. Note that the 32bit code already exports these symbols. Signed-off-By: Sonny Rao Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c index 71f1415..ace85fa 100644 --- a/arch/powerpc/mm/init_64.c +++ b/arch/powerpc/mm/init_64.c @@ -79,7 +79,9 @@ #endif /* CONFIG_PPC_STD_MMU_64 */ phys_addr_t memstart_addr = ~0; +EXPORT_SYMBOL_GPL(memstart_addr); phys_addr_t kernstart_addr; +EXPORT_SYMBOL_GPL(kernstart_addr); void free_initmem(void) { -- cgit v0.10.2 From 9904b00593f548156962764f67b1bb23f4da56fc Mon Sep 17 00:00:00 2001 From: Denis Kirjanov Date: Thu, 29 Jul 2010 22:04:39 +0000 Subject: powerpc: Use is_32bit_task() helper to test 32 bit binary Use is_32bit_task() helper to test 32 bit binary. Signed-off-by: Denis Kirjanov Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 91356ff..986fedf 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -728,7 +728,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, p->thread.regs = childregs; if (clone_flags & CLONE_SETTLS) { #ifdef CONFIG_PPC64 - if (!test_thread_flag(TIF_32BIT)) + if (!is_32bit_task()) childregs->gpr[13] = childregs->gpr[6]; else #endif @@ -823,7 +823,7 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) regs->nip = start; regs->msr = MSR_USER; #else - if (!test_thread_flag(TIF_32BIT)) { + if (!is_32bit_task()) { unsigned long entry, toc; /* start is a relocated pointer to the function descriptor for @@ -995,7 +995,7 @@ int sys_clone(unsigned long clone_flags, unsigned long usp, if (usp == 0) usp = regs->gpr[1]; /* stack pointer for child */ #ifdef CONFIG_PPC64 - if (test_thread_flag(TIF_32BIT)) { + if (is_32bit_task()) { parent_tidp = TRUNC_PTR(parent_tidp); child_tidp = TRUNC_PTR(child_tidp); } -- cgit v0.10.2 From 3469270807ffde921ad36f90d7b8c8e095d3e4e8 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 2 Aug 2010 20:35:18 +0000 Subject: powerpc/mm: Fix vsid_scrample typo The code is wrapped in an #if 0, but it's wrong so we may as well fix it. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h index 0e398cf..acac35d 100644 --- a/arch/powerpc/include/asm/mmu-hash64.h +++ b/arch/powerpc/include/asm/mmu-hash64.h @@ -433,7 +433,7 @@ typedef struct { * with. However gcc is not clever enough to compute the * modulus (2^n-1) without a second multiply. */ -#define vsid_scrample(protovsid, size) \ +#define vsid_scramble(protovsid, size) \ ((((protovsid) * VSID_MULTIPLIER_##size) % VSID_MODULUS_##size)) #else /* 1 */ -- cgit v0.10.2 From 249ec2287579d578ea72593dc3b30a00121c4075 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 2 Aug 2010 20:39:41 +0000 Subject: powerpc/kdump: Stop all other CPUs before running crash handlers During kdump we run the crash handlers first then stop all other CPUs. We really want to stop all CPUs as close to the fail as possible and also have a very controlled environment for running the crash handlers, so it makes sense to reverse the order. Signed-off-by: Anton Blanchard Acked-by: Matt Evans Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index 417f7b0..4457382 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c @@ -402,6 +402,18 @@ void default_machine_crash_shutdown(struct pt_regs *regs) */ hard_irq_disable(); + /* + * Make a note of crashing cpu. Will be used in machine_kexec + * such that another IPI will not be sent. + */ + crashing_cpu = smp_processor_id(); + crash_save_cpu(regs, crashing_cpu); + crash_kexec_prepare_cpus(crashing_cpu); + cpu_set(crashing_cpu, cpus_in_crash); +#if defined(CONFIG_PPC_STD_MMU_64) && defined(CONFIG_SMP) + crash_kexec_wait_realmode(crashing_cpu); +#endif + for_each_irq(i) { struct irq_desc *desc = irq_to_desc(i); @@ -438,18 +450,8 @@ void default_machine_crash_shutdown(struct pt_regs *regs) crash_shutdown_cpu = -1; __debugger_fault_handler = old_handler; - /* - * Make a note of crashing cpu. Will be used in machine_kexec - * such that another IPI will not be sent. - */ - crashing_cpu = smp_processor_id(); - crash_save_cpu(regs, crashing_cpu); - crash_kexec_prepare_cpus(crashing_cpu); - cpu_set(crashing_cpu, cpus_in_crash); crash_kexec_stop_spus(); -#if defined(CONFIG_PPC_STD_MMU_64) && defined(CONFIG_SMP) - crash_kexec_wait_realmode(crashing_cpu); -#endif + if (ppc_md.kexec_cpu_down) ppc_md.kexec_cpu_down(1, 0); } -- cgit v0.10.2 From d1efa2a7551a10006055e0ac2870b4b6077df8ef Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 3 Aug 2010 09:50:32 +0000 Subject: powerpc/powermac: Drop unnecessary of_node_put for_each_node_by_name only exits when its first argument is NULL, and a subsequent call to of_node_put on that argument is unnecessary. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ iterator name for_each_node_by_name; expression np,E; identifier l; @@ for_each_node_by_name(np,...) { ... when != break; when != goto l; } ... when != np = E - of_node_put(np); // Signed-off-by: Julia Lawall Reviewed-by: Grant Likely Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c index 39df6ab..6e26068 100644 --- a/arch/powerpc/platforms/powermac/feature.c +++ b/arch/powerpc/platforms/powermac/feature.c @@ -2878,7 +2878,6 @@ set_initial_features(void) core99_airport_enable(np, 0, 0); } } - of_node_put(np); } /* On all machines that support sound PM, switch sound off */ diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index ab2027c..3bc075c 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c @@ -1155,13 +1155,11 @@ void __init pmac_pcibios_after_init(void) pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, nd, 0, 0); } } - of_node_put(nd); for_each_node_by_name(nd, "ethernet") { if (nd->parent && of_device_is_compatible(nd, "gmac") && of_device_is_compatible(nd->parent, "uni-north")) pmac_call_feature(PMAC_FTR_GMAC_ENABLE, nd, 0, 0); } - of_node_put(nd); } void pmac_pci_fixup_cardbus(struct pci_dev* dev) -- cgit v0.10.2 From 5fba610ec94a1290fc299ea051e47d55da9059ba Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 3 Aug 2010 11:33:43 +0000 Subject: powerpc/powermac: Drop unnecessary null test for_each_node_by_name binds its first argument to a non-null value, and thus any null test on the value of that argument is superfluous. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ iterator I; expression x,E; @@ I(x,...) { <... ( - (x != NULL) && E ...> } // Signed-off-by: Julia Lawall Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c index 6e26068..df42399 100644 --- a/arch/powerpc/platforms/powermac/feature.c +++ b/arch/powerpc/platforms/powermac/feature.c @@ -2873,7 +2873,7 @@ set_initial_features(void) /* Switch airport off */ for_each_node_by_name(np, "radio") { - if (np && np->parent == macio_chips[0].of_node) { + if (np->parent == macio_chips[0].of_node) { macio_chips[0].flags |= MACIO_FLAG_AIRPORT_ON; core99_airport_enable(np, 0, 0); } -- cgit v0.10.2 From da9bef6735d3c5c1c0cd16717acee18d56dd59f5 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 3 Aug 2010 11:35:17 +0000 Subject: powerpc/pci: Drop unnecessary null test list_for_each_entry binds its first argument to a non-null value, and thus any null test on the value of that argument is superfluous. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ iterator I; expression x,E,E1,E2; statement S,S1,S2; @@ I(x,...) { <... - if (x != NULL || ...) S ...> } // Signed-off-by: Julia Lawall Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/pci_of_scan.c b/arch/powerpc/kernel/pci_of_scan.c index 6ddb795f..62dd363 100644 --- a/arch/powerpc/kernel/pci_of_scan.c +++ b/arch/powerpc/kernel/pci_of_scan.c @@ -336,8 +336,7 @@ static void __devinit __of_scan_bus(struct device_node *node, if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { struct device_node *child = pci_device_to_OF_node(dev); - if (dev) - of_scan_pci_bridge(child, dev); + of_scan_pci_bridge(child, dev); } } } -- cgit v0.10.2 From a7c2bb8279d20d853e43c34584eaf2b039de8026 Mon Sep 17 00:00:00 2001 From: "Signed-off-by: Darren Hart" Date: Wed, 4 Aug 2010 18:28:33 +0000 Subject: powerpc: Re-enable preemption before cpu_die() start_secondary() is called shortly after _start and also via cpu_idle()->cpu_die()->pseries_mach_cpu_die() start_secondary() expects a preempt_count() of 0. pseries_mach_cpu_die() is called via the cpu_idle() routine with preemption disabled, resulting in the following repeating message during rapid cpu offline/online tests with CONFIG_PREEMPT=y: BUG: scheduling while atomic: swapper/0/0x00000002 Modules linked in: autofs4 binfmt_misc dm_mirror dm_region_hash dm_log [last unloaded: scsi_wait_scan] Call Trace: [c00000010e7079c0] [c0000000000133ec] .show_stack+0xd8/0x218 (unreliable) [c00000010e707aa0] [c0000000006a47f0] .dump_stack+0x28/0x3c [c00000010e707b20] [c00000000006e7a4] .__schedule_bug+0x7c/0x9c [c00000010e707bb0] [c000000000699d9c] .schedule+0x104/0x800 [c00000010e707cd0] [c000000000015b24] .cpu_idle+0x1c4/0x1d8 [c00000010e707d70] [c0000000006aa1b4] .start_secondary+0x398/0x3d4 [c00000010e707e30] [c000000000008278] .start_secondary_resume+0x10/0x14 Move the cpu_die() call inside the existing preemption enabled block of cpu_idle(). This is safe as the idle task is affined to a single CPU so the debug_smp_processor_id() tests (from cpu_should_die()) won't trigger as we are in a "migration disabled" region. Signed-off-by: Darren Hart Acked-by: Will Schmidt Cc: Thomas Gleixner Cc: Nathan Fontenot Cc: Robert Jennings Cc: Brian King Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c index 049dda6..39a2baa 100644 --- a/arch/powerpc/kernel/idle.c +++ b/arch/powerpc/kernel/idle.c @@ -94,9 +94,9 @@ void cpu_idle(void) HMT_medium(); ppc64_runlatch_on(); tick_nohz_restart_sched_tick(); + preempt_enable_no_resched(); if (cpu_should_die()) cpu_die(); - preempt_enable_no_resched(); schedule(); preempt_disable(); } -- cgit v0.10.2 From 6685a477494ceb063c10300891e48895bb1843c9 Mon Sep 17 00:00:00 2001 From: "Signed-off-by: Darren Hart" Date: Wed, 4 Aug 2010 18:28:34 +0000 Subject: powerpc: Silence __cpu_up() under normal operation During CPU offline/online tests __cpu_up would flood the logs with the following message: Processor 0 found. This provides no useful information to the user as there is no context provided, and since the operation was a success (to this point) it is expected that the CPU will come back online, providing all the feedback necessary. Change the "Processor found" message to DBG() similar to other such messages in the same function. Also, add an appropriate log level for the "Processor is stuck" message. Signed-off-by: Darren Hart Acked-by: Will Schmidt Cc: Thomas Gleixner Cc: Nathan Fontenot Cc: Robert Jennings Cc: Brian King Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index a61b3dd..0008bc5 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -427,11 +427,11 @@ int __cpuinit __cpu_up(unsigned int cpu) #endif if (!cpu_callin_map[cpu]) { - printk("Processor %u is stuck.\n", cpu); + printk(KERN_ERR "Processor %u is stuck.\n", cpu); return -ENOENT; } - printk("Processor %u found.\n", cpu); + DBG("Processor %u found.\n", cpu); if (smp_ops->give_timebase) smp_ops->give_timebase(); -- cgit v0.10.2 From 1afb56cf977ab41bff4fc6bf9e5864770b19b880 Mon Sep 17 00:00:00 2001 From: "Signed-off-by: Darren Hart" Date: Wed, 4 Aug 2010 18:28:35 +0000 Subject: powerpc: Silence xics_migrate_irqs_away() during cpu offline All IRQs are migrated away from a CPU that is being offlined so the following messages suggest a problem when the system is behaving as designed: IRQ 262 affinity broken off cpu 1 IRQ 17 affinity broken off cpu 0 IRQ 18 affinity broken off cpu 0 IRQ 19 affinity broken off cpu 0 IRQ 256 affinity broken off cpu 0 IRQ 261 affinity broken off cpu 0 IRQ 262 affinity broken off cpu 0 Don't print these messages when the CPU is not online. Signed-off-by: Darren Hart Acked-by: Will Schmidt Cc: Thomas Gleixner Cc: Nathan Fontenot Cc: Robert Jennings Cc: Brian King Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index 5b22b07..93834b0 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -928,8 +928,10 @@ void xics_migrate_irqs_away(void) if (xics_status[0] != hw_cpu) goto unlock; - printk(KERN_WARNING "IRQ %u affinity broken off cpu %u\n", - virq, cpu); + /* This is expected during cpu offline. */ + if (cpu_online(cpu)) + printk(KERN_WARNING "IRQ %u affinity broken off cpu %u\n", + virq, cpu); /* Reset affinity to all cpus */ cpumask_setall(irq_to_desc(virq)->affinity); -- cgit v0.10.2 From 954e6da54b2f3a5e2634312db800bc1395c509ee Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Thu, 5 Aug 2010 07:42:11 +0000 Subject: powerpc: Correct smt_enabled=X boot option for > 2 threads per core The 'smt_enabled=X' boot option does not handle values of X > 2. For Power 7 processors with smt modes of 0,1,2,3, and 4 this does not work. This patch allows the smt_enabled option to be set to any value limited to a max equal to the number of threads per core. Signed-off-by: Nathan Fontenot Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 1bee4b6..e72690e 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -95,7 +95,7 @@ int ucache_bsize; #ifdef CONFIG_SMP -static int smt_enabled_cmdline; +static char *smt_enabled_cmdline; /* Look for ibm,smt-enabled OF option */ static void check_smt_enabled(void) @@ -103,37 +103,46 @@ static void check_smt_enabled(void) struct device_node *dn; const char *smt_option; - /* Allow the command line to overrule the OF option */ - if (smt_enabled_cmdline) - return; - - dn = of_find_node_by_path("/options"); - - if (dn) { - smt_option = of_get_property(dn, "ibm,smt-enabled", NULL); + /* Default to enabling all threads */ + smt_enabled_at_boot = threads_per_core; - if (smt_option) { - if (!strcmp(smt_option, "on")) - smt_enabled_at_boot = 1; - else if (!strcmp(smt_option, "off")) - smt_enabled_at_boot = 0; - } - } + /* Allow the command line to overrule the OF option */ + if (smt_enabled_cmdline) { + if (!strcmp(smt_enabled_cmdline, "on")) + smt_enabled_at_boot = threads_per_core; + else if (!strcmp(smt_enabled_cmdline, "off")) + smt_enabled_at_boot = 0; + else { + long smt; + int rc; + + rc = strict_strtol(smt_enabled_cmdline, 10, &smt); + if (!rc) + smt_enabled_at_boot = + min(threads_per_core, (int)smt); + } + } else { + dn = of_find_node_by_path("/options"); + if (dn) { + smt_option = of_get_property(dn, "ibm,smt-enabled", + NULL); + + if (smt_option) { + if (!strcmp(smt_option, "on")) + smt_enabled_at_boot = threads_per_core; + else if (!strcmp(smt_option, "off")) + smt_enabled_at_boot = 0; + } + + of_node_put(dn); + } + } } /* Look for smt-enabled= cmdline option */ static int __init early_smt_enabled(char *p) { - smt_enabled_cmdline = 1; - - if (!p) - return 0; - - if (!strcmp(p, "on") || !strcmp(p, "1")) - smt_enabled_at_boot = 1; - else if (!strcmp(p, "off") || !strcmp(p, "0")) - smt_enabled_at_boot = 0; - + smt_enabled_cmdline = p; return 0; } early_param("smt-enabled", early_smt_enabled); @@ -380,8 +389,8 @@ void __init setup_system(void) */ xmon_setup(); - check_smt_enabled(); smp_setup_cpu_maps(); + check_smt_enabled(); #ifdef CONFIG_SMP /* Release secondary cpus out of their spinloops at 0x60 now that diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index 3b1bf61..0317cce 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c @@ -182,10 +182,13 @@ static int smp_pSeries_cpu_bootable(unsigned int nr) /* Special case - we inhibit secondary thread startup * during boot if the user requests it. */ - if (system_state < SYSTEM_RUNNING && - cpu_has_feature(CPU_FTR_SMT) && - !smt_enabled_at_boot && cpu_thread_in_core(nr) != 0) - return 0; + if (system_state < SYSTEM_RUNNING && cpu_has_feature(CPU_FTR_SMT)) { + if (!smt_enabled_at_boot && cpu_thread_in_core(nr) != 0) + return 0; + if (smt_enabled_at_boot + && cpu_thread_in_core(nr) >= smt_enabled_at_boot) + return 0; + } return 1; } -- cgit v0.10.2 From 4138d65333fa8961714441ed40229ea8cbeaf7e5 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Fri, 6 Aug 2010 03:28:19 +0000 Subject: powerpc: Inline ppc64_runlatch_off I'm sick of seeing ppc64_runlatch_off in our profiles, so inline it into the callers. To avoid a mess of circular includes I didn't add it as an inline function. Signed-off-by: Anton Blanchard Acked-by: Olof Johansson Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index d8be016..ff0005eec 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -951,7 +951,14 @@ #ifdef CONFIG_PPC64 extern void ppc64_runlatch_on(void); -extern void ppc64_runlatch_off(void); +extern void __ppc64_runlatch_off(void); + +#define ppc64_runlatch_off() \ + do { \ + if (cpu_has_feature(CPU_FTR_CTRL) && \ + test_thread_flag(TIF_RUNLATCH)) \ + __ppc64_runlatch_off(); \ + } while (0) extern unsigned long scom970_read(unsigned int address); extern void scom970_write(unsigned int address, unsigned long value); diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 986fedf..b1c648a 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -1199,19 +1199,17 @@ void ppc64_runlatch_on(void) } } -void ppc64_runlatch_off(void) +void __ppc64_runlatch_off(void) { unsigned long ctrl; - if (cpu_has_feature(CPU_FTR_CTRL) && test_thread_flag(TIF_RUNLATCH)) { - HMT_medium(); + HMT_medium(); - clear_thread_flag(TIF_RUNLATCH); + clear_thread_flag(TIF_RUNLATCH); - ctrl = mfspr(SPRN_CTRLF); - ctrl &= ~CTRL_RUNLATCH; - mtspr(SPRN_CTRLT, ctrl); - } + ctrl = mfspr(SPRN_CTRLF); + ctrl &= ~CTRL_RUNLATCH; + mtspr(SPRN_CTRLT, ctrl); } #endif -- cgit v0.10.2 From 7aa241fdcef2a1d6587fe4c390e9fdbfc767af28 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 11 Aug 2010 16:42:48 +0000 Subject: powerpc: Fix bogus it_blocksize in VIO iommu code When looking at some issues with the virtual ethernet driver I noticed that TCE allocation was following a very strange pattern: address 00e9000 length 2048 address 0409000 length 2048 <----- address 0429000 length 2048 address 0449000 length 2048 address 0469000 length 2048 address 0489000 length 2048 address 04a9000 length 2048 address 04c9000 length 2048 address 04e9000 length 2048 address 4009000 length 2048 <----- address 4029000 length 2048 Huge unexplained gaps in what should be an empty TCE table. It turns out it_blocksize, the amount we want to align the next allocation to, was c0000000fe903b20. Completely bogus. Initialise it to something reasonable in the VIO IOMMU code, and use kzalloc everywhere to protect against this when we next add a non compulsary field to iommu code and forget to initialise it. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index 00b9436..fa3469d 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -1059,7 +1059,7 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) if (!dma_window) return NULL; - tbl = kmalloc(sizeof(*tbl), GFP_KERNEL); + tbl = kzalloc(sizeof(*tbl), GFP_KERNEL); if (tbl == NULL) return NULL; @@ -1072,6 +1072,7 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) tbl->it_offset = offset >> IOMMU_PAGE_SHIFT; tbl->it_busno = 0; tbl->it_type = TCE_VB; + tbl->it_blocksize = 16; return iommu_init_table(tbl, -1); } diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index 58b13ce..26a0671 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -477,7 +477,7 @@ cell_iommu_setup_window(struct cbe_iommu *iommu, struct device_node *np, ioid = cell_iommu_get_ioid(np); - window = kmalloc_node(sizeof(*window), GFP_KERNEL, iommu->nid); + window = kzalloc_node(sizeof(*window), GFP_KERNEL, iommu->nid); BUG_ON(window == NULL); window->offset = offset; diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c index ce61cea..d8b7633 100644 --- a/arch/powerpc/platforms/iseries/iommu.c +++ b/arch/powerpc/platforms/iseries/iommu.c @@ -184,7 +184,7 @@ static void pci_dma_dev_setup_iseries(struct pci_dev *pdev) BUG_ON(lsn == NULL); - tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); + tbl = kzalloc(sizeof(struct iommu_table), GFP_KERNEL); iommu_table_getparms_iSeries(pdn->busno, *lsn, 0, tbl); diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 395848e..a77bcae 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -403,7 +403,7 @@ static void pci_dma_bus_setup_pSeries(struct pci_bus *bus) pci->phb->dma_window_size = 0x8000000ul; pci->phb->dma_window_base_cur = 0x8000000ul; - tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, + tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL, pci->phb->node); iommu_table_setparms(pci->phb, dn, tbl); @@ -448,7 +448,7 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus) pdn->full_name, ppci->iommu_table); if (!ppci->iommu_table) { - tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, + tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL, ppci->phb->node); iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window, bus->number); @@ -478,7 +478,7 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev) struct pci_controller *phb = PCI_DN(dn)->phb; pr_debug(" --> first child, no bridge. Allocating iommu table.\n"); - tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, + tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL, phb->node); iommu_table_setparms(phb, dn, tbl); PCI_DN(dn)->iommu_table = iommu_init_table(tbl, phb->node); @@ -544,7 +544,7 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) pci = PCI_DN(pdn); if (!pci->iommu_table) { - tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, + tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL, pci->phb->node); iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window, pci->phb->bus->number); -- cgit v0.10.2 From f761622e59433130bc33ad086ce219feee9eb961 Mon Sep 17 00:00:00 2001 From: Matt Evans Date: Thu, 12 Aug 2010 20:58:28 +0000 Subject: powerpc: Initialise paca->kstack before early_setup_secondary As early setup calls down to slb_initialize(), we must have kstack initialised before checking "should we add a bolted SLB entry for our kstack?" Failing to do so means stack access requires an SLB miss exception to refill an entry dynamically, if the stack isn't accessible via SLB(0) (kernel text & static data). It's not always allowable to take such a miss, and intermittent crashes will result. Primary CPUs don't have this issue; an SLB entry is not bolted for their stack anyway (as that lives within SLB(0)). This patch therefore only affects the init of secondaries. Signed-off-by: Matt Evans Cc: stable Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 844a44b..4d6681d 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -572,9 +572,6 @@ __secondary_start: /* Set thread priority to MEDIUM */ HMT_MEDIUM - /* Do early setup for that CPU (stab, slb, hash table pointer) */ - bl .early_setup_secondary - /* Initialize the kernel stack. Just a repeat for iSeries. */ LOAD_REG_ADDR(r3, current_set) sldi r28,r24,3 /* get current_set[cpu#] */ @@ -582,6 +579,9 @@ __secondary_start: addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD std r1,PACAKSAVE(r13) + /* Do early setup for that CPU (stab, slb, hash table pointer) */ + bl .early_setup_secondary + /* Clear backchain so we get nice backtraces */ li r7,0 mtlr r7 -- cgit v0.10.2 From c686ecf5040d287a68d4fca7f1948472f556a6d3 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Sun, 15 Aug 2010 22:26:56 +0000 Subject: powerpc: Fix typo in uImage target Commit e32e78c5ee8aadef020fbaecbe6fb741ed9029fd (powerpc: fix build with make 3.82) introduced a typo in uImage target and broke building uImage: make: *** No rule to make target `uImage'. Stop. Signed-off-by: Anatolij Gustschin Cc: stable Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index e3ea151..b7212b6 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -164,7 +164,7 @@ drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ all: zImage # With make 3.82 we cannot mix normal and wildcard targets -BOOT_TARGETS1 := zImage zImage.initrd uImaged +BOOT_TARGETS1 := zImage zImage.initrd uImage BOOT_TARGETS2 := zImage% dtbImage% treeImage.% cuImage.% simpleImage.% PHONY += $(BOOT_TARGETS1) $(BOOT_TARGETS2) -- cgit v0.10.2 From 76ec01dbb70353928a9cee826502073ae928bbba Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Wed, 18 Aug 2010 08:27:55 +0000 Subject: powerpc/pci: Fix checking for child bridges in PCI code. pci_device_to_OF_node() can return null, and list_for_each_entry will never enter the loop when dev is NULL, so it looks like this test is a typo. Reported-by: Julia Lawall Signed-off-by: Grant Likely Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/pci_of_scan.c b/arch/powerpc/kernel/pci_of_scan.c index 62dd363..e751506 100644 --- a/arch/powerpc/kernel/pci_of_scan.c +++ b/arch/powerpc/kernel/pci_of_scan.c @@ -336,7 +336,8 @@ static void __devinit __of_scan_bus(struct device_node *node, if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { struct device_node *child = pci_device_to_OF_node(dev); - of_scan_pci_bridge(child, dev); + if (child) + of_scan_pci_bridge(child, dev); } } } -- cgit v0.10.2 From bcc30d37582b3822ae24712e894379ccd8298e8f Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Thu, 19 Aug 2010 05:15:37 +0000 Subject: powerpc: Wire up fanotify_init, fanotify_mark, prlimit64 syscalls Signed-off-by: Andreas Schwab Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h index a5ee345..3d21266 100644 --- a/arch/powerpc/include/asm/systbl.h +++ b/arch/powerpc/include/asm/systbl.h @@ -326,3 +326,6 @@ SYSCALL_SPU(perf_event_open) COMPAT_SYS_SPU(preadv) COMPAT_SYS_SPU(pwritev) COMPAT_SYS(rt_tgsigqueueinfo) +SYSCALL(fanotify_init) +COMPAT_SYS(fanotify_mark) +SYSCALL_SPU(prlimit64) diff --git a/arch/powerpc/include/asm/unistd.h b/arch/powerpc/include/asm/unistd.h index f0a1026..597e6f9 100644 --- a/arch/powerpc/include/asm/unistd.h +++ b/arch/powerpc/include/asm/unistd.h @@ -345,10 +345,13 @@ #define __NR_preadv 320 #define __NR_pwritev 321 #define __NR_rt_tgsigqueueinfo 322 +#define __NR_fanotify_init 323 +#define __NR_fanotify_mark 324 +#define __NR_prlimit64 325 #ifdef __KERNEL__ -#define __NR_syscalls 323 +#define __NR_syscalls 326 #define __NR__exit __NR_exit #define NR_syscalls __NR_syscalls diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c index 20fd701..b1b6043 100644 --- a/arch/powerpc/kernel/sys_ppc32.c +++ b/arch/powerpc/kernel/sys_ppc32.c @@ -616,3 +616,11 @@ asmlinkage long compat_sys_sync_file_range2(int fd, unsigned int flags, return sys_sync_file_range(fd, offset, nbytes, flags); } + +asmlinkage long compat_sys_fanotify_mark(int fanotify_fd, unsigned int flags, + unsigned mask_hi, unsigned mask_lo, + int dfd, const char __user *pathname) +{ + u64 mask = ((u64)mask_hi << 32) | mask_lo; + return sys_fanotify_mark(fanotify_fd, flags, mask, dfd, pathname); +} -- cgit v0.10.2 From 4cc4587fb14bb04fbc68096cc3780b4e6aa88fe7 Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Sun, 22 Aug 2010 06:23:17 +0000 Subject: via-pmu: Add compat_pmu_ioctl The ioctls are actually compatible, but due to historical mistake the numbers differ between 32bit and 64bit. Signed-off-by: Andreas Schwab Acked-by: Arnd Bergmann Signed-off-by: Benjamin Herrenschmidt diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 35bc273..2d17e76 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -2349,11 +2350,52 @@ static long pmu_unlocked_ioctl(struct file *filp, return ret; } +#ifdef CONFIG_COMPAT +#define PMU_IOC_GET_BACKLIGHT32 _IOR('B', 1, compat_size_t) +#define PMU_IOC_SET_BACKLIGHT32 _IOW('B', 2, compat_size_t) +#define PMU_IOC_GET_MODEL32 _IOR('B', 3, compat_size_t) +#define PMU_IOC_HAS_ADB32 _IOR('B', 4, compat_size_t) +#define PMU_IOC_CAN_SLEEP32 _IOR('B', 5, compat_size_t) +#define PMU_IOC_GRAB_BACKLIGHT32 _IOR('B', 6, compat_size_t) + +static long compat_pmu_ioctl (struct file *filp, u_int cmd, u_long arg) +{ + switch (cmd) { + case PMU_IOC_SLEEP: + break; + case PMU_IOC_GET_BACKLIGHT32: + cmd = PMU_IOC_GET_BACKLIGHT; + break; + case PMU_IOC_SET_BACKLIGHT32: + cmd = PMU_IOC_SET_BACKLIGHT; + break; + case PMU_IOC_GET_MODEL32: + cmd = PMU_IOC_GET_MODEL; + break; + case PMU_IOC_HAS_ADB32: + cmd = PMU_IOC_HAS_ADB; + break; + case PMU_IOC_CAN_SLEEP32: + cmd = PMU_IOC_CAN_SLEEP; + break; + case PMU_IOC_GRAB_BACKLIGHT32: + cmd = PMU_IOC_GRAB_BACKLIGHT; + break; + default: + return -ENOIOCTLCMD; + } + return pmu_unlocked_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); +} +#endif + static const struct file_operations pmu_device_fops = { .read = pmu_read, .write = pmu_write, .poll = pmu_fpoll, .unlocked_ioctl = pmu_unlocked_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = compat_pmu_ioctl, +#endif .open = pmu_open, .release = pmu_release, }; -- cgit v0.10.2 From 314b389b1795286400f109a25e9c2f02ab3b9b15 Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Mon, 23 Aug 2010 07:36:41 +0000 Subject: powerpc: Fix config dependency problem with MPIC_U3_HT_IRQS MPIC_U3_HT_IRQS is selected both by PPC_PMAC64 and PPC_MAPLE, but depends on PPC_MAPLE, so a PPC_PMAC64-only config gets this warning: warning: (PPC_PMAC64 && PPC_PMAC && POWER4 || PPC_MAPLE && PPC64 && PPC_BOOK3S) selects MPIC_U3_HT_IRQS which has unmet direct dependencies (PPC_MAPLE) Fix that by removing the dependency on PPC_MAPLE. Signed-off-by: Andreas Schwab Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index d1663db..81c9208 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -106,8 +106,7 @@ config MMIO_NVRAM config MPIC_U3_HT_IRQS bool - depends on PPC_MAPLE - default y + default n config MPIC_BROKEN_REGREAD bool -- cgit v0.10.2 From 25edd6946a1d74e5e77813c2324a0908c68bcf9e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 23 Aug 2010 23:10:57 -0700 Subject: sparc64: Get rid of indirect p1275 PROM call buffer. This is based upon a report by Meelis Roos showing that it's possible that we'll try to fetch a property that is 32K in size with some devices. With the current fixed 3K buffer we use for moving data in and out of the firmware during PROM calls, that simply won't work. In fact, it will scramble random kernel data during bootup. The reasoning behind the temporary buffer is entirely historical. It used to be the case that we had problems referencing dynamic kernel memory (including the stack) early in the boot process before we explicitly told the firwmare to switch us over to the kernel trap table. So what we did was always give the firmware buffers that were locked into the main kernel image. But we no longer have problems like that, so get rid of all of this indirect bounce buffering. Besides fixing Meelis's bug, this also makes the kernel data about 3K smaller. It was also discovered during these conversions that the implementation of prom_retain() was completely wrong, so that was fixed here as well. Currently that interface is not in use. Reported-by: Meelis Roos Tested-by: Meelis Roos Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/oplib_64.h b/arch/sparc/include/asm/oplib_64.h index a5db031..3e0b2d6 100644 --- a/arch/sparc/include/asm/oplib_64.h +++ b/arch/sparc/include/asm/oplib_64.h @@ -185,9 +185,8 @@ extern int prom_getunumber(int syndrome_code, char *buf, int buflen); /* Retain physical memory to the caller across soft resets. */ -extern unsigned long prom_retain(const char *name, - unsigned long pa_low, unsigned long pa_high, - long size, long align); +extern int prom_retain(const char *name, unsigned long size, + unsigned long align, unsigned long *paddr); /* Load explicit I/D TLB entries into the calling processor. */ extern long prom_itlb_load(unsigned long index, @@ -287,26 +286,6 @@ extern void prom_sun4v_guest_soft_state(void); extern int prom_ihandle2path(int handle, char *buffer, int bufsize); /* Client interface level routines. */ -extern long p1275_cmd(const char *, long, ...); - -#if 0 -#define P1275_SIZE(x) ((((long)((x) / 32)) << 32) | (x)) -#else -#define P1275_SIZE(x) x -#endif - -/* We support at most 16 input and 1 output argument */ -#define P1275_ARG_NUMBER 0 -#define P1275_ARG_IN_STRING 1 -#define P1275_ARG_OUT_BUF 2 -#define P1275_ARG_OUT_32B 3 -#define P1275_ARG_IN_FUNCTION 4 -#define P1275_ARG_IN_BUF 5 -#define P1275_ARG_IN_64B 6 - -#define P1275_IN(x) ((x) & 0xf) -#define P1275_OUT(x) (((x) << 4) & 0xf0) -#define P1275_INOUT(i,o) (P1275_IN(i)|P1275_OUT(o)) -#define P1275_ARG(n,x) ((x) << ((n)*3 + 8)) +extern void p1275_cmd_direct(unsigned long *); #endif /* !(__SPARC64_OPLIB_H) */ diff --git a/arch/sparc/prom/cif.S b/arch/sparc/prom/cif.S index 5f27ad7..9c86b4b 100644 --- a/arch/sparc/prom/cif.S +++ b/arch/sparc/prom/cif.S @@ -9,18 +9,18 @@ #include .text - .globl prom_cif_interface -prom_cif_interface: - sethi %hi(p1275buf), %o0 - or %o0, %lo(p1275buf), %o0 - ldx [%o0 + 0x010], %o1 ! prom_cif_stack - save %o1, -192, %sp - ldx [%i0 + 0x008], %l2 ! prom_cif_handler + .globl prom_cif_direct +prom_cif_direct: + sethi %hi(p1275buf), %o1 + or %o1, %lo(p1275buf), %o1 + ldx [%o1 + 0x0010], %o2 ! prom_cif_stack + save %o2, -192, %sp + ldx [%i1 + 0x0008], %l2 ! prom_cif_handler mov %g4, %l0 mov %g5, %l1 mov %g6, %l3 call %l2 - add %i0, 0x018, %o0 ! prom_args + mov %i0, %o0 ! prom_args mov %l0, %g4 mov %l1, %g5 mov %l3, %g6 diff --git a/arch/sparc/prom/console_64.c b/arch/sparc/prom/console_64.c index f55d58a..10322dc 100644 --- a/arch/sparc/prom/console_64.c +++ b/arch/sparc/prom/console_64.c @@ -21,14 +21,22 @@ extern int prom_stdin, prom_stdout; inline int prom_nbgetchar(void) { + unsigned long args[7]; char inc; - if (p1275_cmd("read", P1275_ARG(1,P1275_ARG_OUT_BUF)| - P1275_INOUT(3,1), - prom_stdin, &inc, P1275_SIZE(1)) == 1) + args[0] = (unsigned long) "read"; + args[1] = 3; + args[2] = 1; + args[3] = (unsigned int) prom_stdin; + args[4] = (unsigned long) &inc; + args[5] = 1; + args[6] = (unsigned long) -1; + + p1275_cmd_direct(args); + + if (args[6] == 1) return inc; - else - return -1; + return -1; } /* Non blocking put character to console device, returns -1 if @@ -37,12 +45,22 @@ prom_nbgetchar(void) inline int prom_nbputchar(char c) { + unsigned long args[7]; char outc; outc = c; - if (p1275_cmd("write", P1275_ARG(1,P1275_ARG_IN_BUF)| - P1275_INOUT(3,1), - prom_stdout, &outc, P1275_SIZE(1)) == 1) + + args[0] = (unsigned long) "write"; + args[1] = 3; + args[2] = 1; + args[3] = (unsigned int) prom_stdout; + args[4] = (unsigned long) &outc; + args[5] = 1; + args[6] = (unsigned long) -1; + + p1275_cmd_direct(args); + + if (args[6] == 1) return 0; else return -1; @@ -67,7 +85,15 @@ prom_putchar(char c) void prom_puts(const char *s, int len) { - p1275_cmd("write", P1275_ARG(1,P1275_ARG_IN_BUF)| - P1275_INOUT(3,1), - prom_stdout, s, P1275_SIZE(len)); + unsigned long args[7]; + + args[0] = (unsigned long) "write"; + args[1] = 3; + args[2] = 1; + args[3] = (unsigned int) prom_stdout; + args[4] = (unsigned long) s; + args[5] = len; + args[6] = (unsigned long) -1; + + p1275_cmd_direct(args); } diff --git a/arch/sparc/prom/devops_64.c b/arch/sparc/prom/devops_64.c index 9dbd803..a017119 100644 --- a/arch/sparc/prom/devops_64.c +++ b/arch/sparc/prom/devops_64.c @@ -18,16 +18,32 @@ int prom_devopen(const char *dstr) { - return p1275_cmd ("open", P1275_ARG(0,P1275_ARG_IN_STRING)| - P1275_INOUT(1,1), - dstr); + unsigned long args[5]; + + args[0] = (unsigned long) "open"; + args[1] = 1; + args[2] = 1; + args[3] = (unsigned long) dstr; + args[4] = (unsigned long) -1; + + p1275_cmd_direct(args); + + return (int) args[4]; } /* Close the device described by device handle 'dhandle'. */ int prom_devclose(int dhandle) { - p1275_cmd ("close", P1275_INOUT(1,0), dhandle); + unsigned long args[4]; + + args[0] = (unsigned long) "close"; + args[1] = 1; + args[2] = 0; + args[3] = (unsigned int) dhandle; + + p1275_cmd_direct(args); + return 0; } @@ -37,5 +53,15 @@ prom_devclose(int dhandle) void prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo) { - p1275_cmd ("seek", P1275_INOUT(3,1), dhandle, seekhi, seeklo); + unsigned long args[7]; + + args[0] = (unsigned long) "seek"; + args[1] = 3; + args[2] = 1; + args[3] = (unsigned int) dhandle; + args[4] = seekhi; + args[5] = seeklo; + args[6] = (unsigned long) -1; + + p1275_cmd_direct(args); } diff --git a/arch/sparc/prom/misc_64.c b/arch/sparc/prom/misc_64.c index 39fc6af..6cb1581 100644 --- a/arch/sparc/prom/misc_64.c +++ b/arch/sparc/prom/misc_64.c @@ -20,10 +20,17 @@ int prom_service_exists(const char *service_name) { - int err = p1275_cmd("test", P1275_ARG(0, P1275_ARG_IN_STRING) | - P1275_INOUT(1, 1), service_name); + unsigned long args[5]; - if (err) + args[0] = (unsigned long) "test"; + args[1] = 1; + args[2] = 1; + args[3] = (unsigned long) service_name; + args[4] = (unsigned long) -1; + + p1275_cmd_direct(args); + + if (args[4]) return 0; return 1; } @@ -31,30 +38,47 @@ int prom_service_exists(const char *service_name) void prom_sun4v_guest_soft_state(void) { const char *svc = "SUNW,soft-state-supported"; + unsigned long args[3]; if (!prom_service_exists(svc)) return; - p1275_cmd(svc, P1275_INOUT(0, 0)); + args[0] = (unsigned long) svc; + args[1] = 0; + args[2] = 0; + p1275_cmd_direct(args); } /* Reset and reboot the machine with the command 'bcommand'. */ void prom_reboot(const char *bcommand) { + unsigned long args[4]; + #ifdef CONFIG_SUN_LDOMS if (ldom_domaining_enabled) ldom_reboot(bcommand); #endif - p1275_cmd("boot", P1275_ARG(0, P1275_ARG_IN_STRING) | - P1275_INOUT(1, 0), bcommand); + args[0] = (unsigned long) "boot"; + args[1] = 1; + args[2] = 0; + args[3] = (unsigned long) bcommand; + + p1275_cmd_direct(args); } /* Forth evaluate the expression contained in 'fstring'. */ void prom_feval(const char *fstring) { + unsigned long args[5]; + if (!fstring || fstring[0] == 0) return; - p1275_cmd("interpret", P1275_ARG(0, P1275_ARG_IN_STRING) | - P1275_INOUT(1, 1), fstring); + args[0] = (unsigned long) "interpret"; + args[1] = 1; + args[2] = 1; + args[3] = (unsigned long) fstring; + args[4] = (unsigned long) -1; + + p1275_cmd_direct(args); } EXPORT_SYMBOL(prom_feval); @@ -68,6 +92,7 @@ extern void smp_release(void); */ void prom_cmdline(void) { + unsigned long args[3]; unsigned long flags; local_irq_save(flags); @@ -76,7 +101,11 @@ void prom_cmdline(void) smp_capture(); #endif - p1275_cmd("enter", P1275_INOUT(0, 0)); + args[0] = (unsigned long) "enter"; + args[1] = 0; + args[2] = 0; + + p1275_cmd_direct(args); #ifdef CONFIG_SMP smp_release(); @@ -90,22 +119,32 @@ void prom_cmdline(void) */ void notrace prom_halt(void) { + unsigned long args[3]; + #ifdef CONFIG_SUN_LDOMS if (ldom_domaining_enabled) ldom_power_off(); #endif again: - p1275_cmd("exit", P1275_INOUT(0, 0)); + args[0] = (unsigned long) "exit"; + args[1] = 0; + args[2] = 0; + p1275_cmd_direct(args); goto again; /* PROM is out to get me -DaveM */ } void prom_halt_power_off(void) { + unsigned long args[3]; + #ifdef CONFIG_SUN_LDOMS if (ldom_domaining_enabled) ldom_power_off(); #endif - p1275_cmd("SUNW,power-off", P1275_INOUT(0, 0)); + args[0] = (unsigned long) "SUNW,power-off"; + args[1] = 0; + args[2] = 0; + p1275_cmd_direct(args); /* if nothing else helps, we just halt */ prom_halt(); @@ -114,10 +153,15 @@ void prom_halt_power_off(void) /* Set prom sync handler to call function 'funcp'. */ void prom_setcallback(callback_func_t funcp) { + unsigned long args[5]; if (!funcp) return; - p1275_cmd("set-callback", P1275_ARG(0, P1275_ARG_IN_FUNCTION) | - P1275_INOUT(1, 1), funcp); + args[0] = (unsigned long) "set-callback"; + args[1] = 1; + args[2] = 1; + args[3] = (unsigned long) funcp; + args[4] = (unsigned long) -1; + p1275_cmd_direct(args); } /* Get the idprom and stuff it into buffer 'idbuf'. Returns the @@ -173,57 +217,61 @@ static int prom_get_memory_ihandle(void) } /* Load explicit I/D TLB entries. */ +static long tlb_load(const char *type, unsigned long index, + unsigned long tte_data, unsigned long vaddr) +{ + unsigned long args[9]; + + args[0] = (unsigned long) prom_callmethod_name; + args[1] = 5; + args[2] = 1; + args[3] = (unsigned long) type; + args[4] = (unsigned int) prom_get_mmu_ihandle(); + args[5] = vaddr; + args[6] = tte_data; + args[7] = index; + args[8] = (unsigned long) -1; + + p1275_cmd_direct(args); + + return (long) args[8]; +} + long prom_itlb_load(unsigned long index, unsigned long tte_data, unsigned long vaddr) { - return p1275_cmd(prom_callmethod_name, - (P1275_ARG(0, P1275_ARG_IN_STRING) | - P1275_ARG(2, P1275_ARG_IN_64B) | - P1275_ARG(3, P1275_ARG_IN_64B) | - P1275_INOUT(5, 1)), - "SUNW,itlb-load", - prom_get_mmu_ihandle(), - /* And then our actual args are pushed backwards. */ - vaddr, - tte_data, - index); + return tlb_load("SUNW,itlb-load", index, tte_data, vaddr); } long prom_dtlb_load(unsigned long index, unsigned long tte_data, unsigned long vaddr) { - return p1275_cmd(prom_callmethod_name, - (P1275_ARG(0, P1275_ARG_IN_STRING) | - P1275_ARG(2, P1275_ARG_IN_64B) | - P1275_ARG(3, P1275_ARG_IN_64B) | - P1275_INOUT(5, 1)), - "SUNW,dtlb-load", - prom_get_mmu_ihandle(), - /* And then our actual args are pushed backwards. */ - vaddr, - tte_data, - index); + return tlb_load("SUNW,dtlb-load", index, tte_data, vaddr); } int prom_map(int mode, unsigned long size, unsigned long vaddr, unsigned long paddr) { - int ret = p1275_cmd(prom_callmethod_name, - (P1275_ARG(0, P1275_ARG_IN_STRING) | - P1275_ARG(3, P1275_ARG_IN_64B) | - P1275_ARG(4, P1275_ARG_IN_64B) | - P1275_ARG(6, P1275_ARG_IN_64B) | - P1275_INOUT(7, 1)), - prom_map_name, - prom_get_mmu_ihandle(), - mode, - size, - vaddr, - 0, - paddr); - + unsigned long args[11]; + int ret; + + args[0] = (unsigned long) prom_callmethod_name; + args[1] = 7; + args[2] = 1; + args[3] = (unsigned long) prom_map_name; + args[4] = (unsigned int) prom_get_mmu_ihandle(); + args[5] = (unsigned int) mode; + args[6] = size; + args[7] = vaddr; + args[8] = 0; + args[9] = paddr; + args[10] = (unsigned long) -1; + + p1275_cmd_direct(args); + + ret = (int) args[10]; if (ret == 0) ret = -1; return ret; @@ -231,40 +279,51 @@ int prom_map(int mode, unsigned long size, void prom_unmap(unsigned long size, unsigned long vaddr) { - p1275_cmd(prom_callmethod_name, - (P1275_ARG(0, P1275_ARG_IN_STRING) | - P1275_ARG(2, P1275_ARG_IN_64B) | - P1275_ARG(3, P1275_ARG_IN_64B) | - P1275_INOUT(4, 0)), - prom_unmap_name, - prom_get_mmu_ihandle(), - size, - vaddr); + unsigned long args[7]; + + args[0] = (unsigned long) prom_callmethod_name; + args[1] = 4; + args[2] = 0; + args[3] = (unsigned long) prom_unmap_name; + args[4] = (unsigned int) prom_get_mmu_ihandle(); + args[5] = size; + args[6] = vaddr; + + p1275_cmd_direct(args); } /* Set aside physical memory which is not touched or modified * across soft resets. */ -unsigned long prom_retain(const char *name, - unsigned long pa_low, unsigned long pa_high, - long size, long align) +int prom_retain(const char *name, unsigned long size, + unsigned long align, unsigned long *paddr) { - /* XXX I don't think we return multiple values correctly. - * XXX OBP supposedly returns pa_low/pa_high here, how does - * XXX it work? + unsigned long args[11]; + + args[0] = (unsigned long) prom_callmethod_name; + args[1] = 5; + args[2] = 3; + args[3] = (unsigned long) "SUNW,retain"; + args[4] = (unsigned int) prom_get_memory_ihandle(); + args[5] = align; + args[6] = size; + args[7] = (unsigned long) name; + args[8] = (unsigned long) -1; + args[9] = (unsigned long) -1; + args[10] = (unsigned long) -1; + + p1275_cmd_direct(args); + + if (args[8]) + return (int) args[8]; + + /* Next we get "phys_high" then "phys_low". On 64-bit + * the phys_high cell is don't care since the phys_low + * cell has the full value. */ + *paddr = args[10]; - /* If align is zero, the pa_low/pa_high args are passed, - * else they are not. - */ - if (align == 0) - return p1275_cmd("SUNW,retain", - (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 2)), - name, pa_low, pa_high, size, align); - else - return p1275_cmd("SUNW,retain", - (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(3, 2)), - name, size, align); + return 0; } /* Get "Unumber" string for the SIMM at the given @@ -277,62 +336,129 @@ int prom_getunumber(int syndrome_code, unsigned long phys_addr, char *buf, int buflen) { - return p1275_cmd(prom_callmethod_name, - (P1275_ARG(0, P1275_ARG_IN_STRING) | - P1275_ARG(3, P1275_ARG_OUT_BUF) | - P1275_ARG(6, P1275_ARG_IN_64B) | - P1275_INOUT(8, 2)), - "SUNW,get-unumber", prom_get_memory_ihandle(), - buflen, buf, P1275_SIZE(buflen), - 0, phys_addr, syndrome_code); + unsigned long args[12]; + + args[0] = (unsigned long) prom_callmethod_name; + args[1] = 7; + args[2] = 2; + args[3] = (unsigned long) "SUNW,get-unumber"; + args[4] = (unsigned int) prom_get_memory_ihandle(); + args[5] = buflen; + args[6] = (unsigned long) buf; + args[7] = 0; + args[8] = phys_addr; + args[9] = (unsigned int) syndrome_code; + args[10] = (unsigned long) -1; + args[11] = (unsigned long) -1; + + p1275_cmd_direct(args); + + return (int) args[10]; } /* Power management extensions. */ void prom_sleepself(void) { - p1275_cmd("SUNW,sleep-self", P1275_INOUT(0, 0)); + unsigned long args[3]; + + args[0] = (unsigned long) "SUNW,sleep-self"; + args[1] = 0; + args[2] = 0; + p1275_cmd_direct(args); } int prom_sleepsystem(void) { - return p1275_cmd("SUNW,sleep-system", P1275_INOUT(0, 1)); + unsigned long args[4]; + + args[0] = (unsigned long) "SUNW,sleep-system"; + args[1] = 0; + args[2] = 1; + args[3] = (unsigned long) -1; + p1275_cmd_direct(args); + + return (int) args[3]; } int prom_wakeupsystem(void) { - return p1275_cmd("SUNW,wakeup-system", P1275_INOUT(0, 1)); + unsigned long args[4]; + + args[0] = (unsigned long) "SUNW,wakeup-system"; + args[1] = 0; + args[2] = 1; + args[3] = (unsigned long) -1; + p1275_cmd_direct(args); + + return (int) args[3]; } #ifdef CONFIG_SMP void prom_startcpu(int cpunode, unsigned long pc, unsigned long arg) { - p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, arg); + unsigned long args[6]; + + args[0] = (unsigned long) "SUNW,start-cpu"; + args[1] = 3; + args[2] = 0; + args[3] = (unsigned int) cpunode; + args[4] = pc; + args[5] = arg; + p1275_cmd_direct(args); } void prom_startcpu_cpuid(int cpuid, unsigned long pc, unsigned long arg) { - p1275_cmd("SUNW,start-cpu-by-cpuid", P1275_INOUT(3, 0), - cpuid, pc, arg); + unsigned long args[6]; + + args[0] = (unsigned long) "SUNW,start-cpu-by-cpuid"; + args[1] = 3; + args[2] = 0; + args[3] = (unsigned int) cpuid; + args[4] = pc; + args[5] = arg; + p1275_cmd_direct(args); } void prom_stopcpu_cpuid(int cpuid) { - p1275_cmd("SUNW,stop-cpu-by-cpuid", P1275_INOUT(1, 0), - cpuid); + unsigned long args[4]; + + args[0] = (unsigned long) "SUNW,stop-cpu-by-cpuid"; + args[1] = 1; + args[2] = 0; + args[3] = (unsigned int) cpuid; + p1275_cmd_direct(args); } void prom_stopself(void) { - p1275_cmd("SUNW,stop-self", P1275_INOUT(0, 0)); + unsigned long args[3]; + + args[0] = (unsigned long) "SUNW,stop-self"; + args[1] = 0; + args[2] = 0; + p1275_cmd_direct(args); } void prom_idleself(void) { - p1275_cmd("SUNW,idle-self", P1275_INOUT(0, 0)); + unsigned long args[3]; + + args[0] = (unsigned long) "SUNW,idle-self"; + args[1] = 0; + args[2] = 0; + p1275_cmd_direct(args); } void prom_resumecpu(int cpunode) { - p1275_cmd("SUNW,resume-cpu", P1275_INOUT(1, 0), cpunode); + unsigned long args[4]; + + args[0] = (unsigned long) "SUNW,resume-cpu"; + args[1] = 1; + args[2] = 0; + args[3] = (unsigned int) cpunode; + p1275_cmd_direct(args); } #endif diff --git a/arch/sparc/prom/p1275.c b/arch/sparc/prom/p1275.c index 2d8b70d..fa6e4e2 100644 --- a/arch/sparc/prom/p1275.c +++ b/arch/sparc/prom/p1275.c @@ -22,13 +22,11 @@ struct { long prom_callback; /* 0x00 */ void (*prom_cif_handler)(long *); /* 0x08 */ unsigned long prom_cif_stack; /* 0x10 */ - unsigned long prom_args [23]; /* 0x18 */ - char prom_buffer [3000]; } p1275buf; extern void prom_world(int); -extern void prom_cif_interface(void); +extern void prom_cif_direct(unsigned long *args); extern void prom_cif_callback(void); /* @@ -36,114 +34,20 @@ extern void prom_cif_callback(void); */ DEFINE_RAW_SPINLOCK(prom_entry_lock); -long p1275_cmd(const char *service, long fmt, ...) +void p1275_cmd_direct(unsigned long *args) { - char *p, *q; unsigned long flags; - int nargs, nrets, i; - va_list list; - long attrs, x; - - p = p1275buf.prom_buffer; raw_local_save_flags(flags); raw_local_irq_restore(PIL_NMI); raw_spin_lock(&prom_entry_lock); - p1275buf.prom_args[0] = (unsigned long)p; /* service */ - strcpy (p, service); - p = (char *)(((long)(strchr (p, 0) + 8)) & ~7); - p1275buf.prom_args[1] = nargs = (fmt & 0x0f); /* nargs */ - p1275buf.prom_args[2] = nrets = ((fmt & 0xf0) >> 4); /* nrets */ - attrs = fmt >> 8; - va_start(list, fmt); - for (i = 0; i < nargs; i++, attrs >>= 3) { - switch (attrs & 0x7) { - case P1275_ARG_NUMBER: - p1275buf.prom_args[i + 3] = - (unsigned)va_arg(list, long); - break; - case P1275_ARG_IN_64B: - p1275buf.prom_args[i + 3] = - va_arg(list, unsigned long); - break; - case P1275_ARG_IN_STRING: - strcpy (p, va_arg(list, char *)); - p1275buf.prom_args[i + 3] = (unsigned long)p; - p = (char *)(((long)(strchr (p, 0) + 8)) & ~7); - break; - case P1275_ARG_OUT_BUF: - (void) va_arg(list, char *); - p1275buf.prom_args[i + 3] = (unsigned long)p; - x = va_arg(list, long); - i++; attrs >>= 3; - p = (char *)(((long)(p + (int)x + 7)) & ~7); - p1275buf.prom_args[i + 3] = x; - break; - case P1275_ARG_IN_BUF: - q = va_arg(list, char *); - p1275buf.prom_args[i + 3] = (unsigned long)p; - x = va_arg(list, long); - i++; attrs >>= 3; - memcpy (p, q, (int)x); - p = (char *)(((long)(p + (int)x + 7)) & ~7); - p1275buf.prom_args[i + 3] = x; - break; - case P1275_ARG_OUT_32B: - (void) va_arg(list, char *); - p1275buf.prom_args[i + 3] = (unsigned long)p; - p += 32; - break; - case P1275_ARG_IN_FUNCTION: - p1275buf.prom_args[i + 3] = - (unsigned long)prom_cif_callback; - p1275buf.prom_callback = va_arg(list, long); - break; - } - } - va_end(list); - prom_world(1); - prom_cif_interface(); + prom_cif_direct(args); prom_world(0); - attrs = fmt >> 8; - va_start(list, fmt); - for (i = 0; i < nargs; i++, attrs >>= 3) { - switch (attrs & 0x7) { - case P1275_ARG_NUMBER: - (void) va_arg(list, long); - break; - case P1275_ARG_IN_STRING: - (void) va_arg(list, char *); - break; - case P1275_ARG_IN_FUNCTION: - (void) va_arg(list, long); - break; - case P1275_ARG_IN_BUF: - (void) va_arg(list, char *); - (void) va_arg(list, long); - i++; attrs >>= 3; - break; - case P1275_ARG_OUT_BUF: - p = va_arg(list, char *); - x = va_arg(list, long); - memcpy (p, (char *)(p1275buf.prom_args[i + 3]), (int)x); - i++; attrs >>= 3; - break; - case P1275_ARG_OUT_32B: - p = va_arg(list, char *); - memcpy (p, (char *)(p1275buf.prom_args[i + 3]), 32); - break; - } - } - va_end(list); - x = p1275buf.prom_args [nargs + 3]; - raw_spin_unlock(&prom_entry_lock); raw_local_irq_restore(flags); - - return x; } void prom_cif_init(void *cif_handler, void *cif_stack) diff --git a/arch/sparc/prom/tree_64.c b/arch/sparc/prom/tree_64.c index 3c0d2dd..9d3f913 100644 --- a/arch/sparc/prom/tree_64.c +++ b/arch/sparc/prom/tree_64.c @@ -16,22 +16,39 @@ #include #include +static int prom_node_to_node(const char *type, int node) +{ + unsigned long args[5]; + + args[0] = (unsigned long) type; + args[1] = 1; + args[2] = 1; + args[3] = (unsigned int) node; + args[4] = (unsigned long) -1; + + p1275_cmd_direct(args); + + return (int) args[4]; +} + /* Return the child of node 'node' or zero if no this node has no * direct descendent. */ inline int __prom_getchild(int node) { - return p1275_cmd ("child", P1275_INOUT(1, 1), node); + return prom_node_to_node("child", node); } inline int prom_getchild(int node) { int cnode; - if(node == -1) return 0; + if (node == -1) + return 0; cnode = __prom_getchild(node); - if(cnode == -1) return 0; - return (int)cnode; + if (cnode == -1) + return 0; + return cnode; } EXPORT_SYMBOL(prom_getchild); @@ -39,10 +56,12 @@ inline int prom_getparent(int node) { int cnode; - if(node == -1) return 0; - cnode = p1275_cmd ("parent", P1275_INOUT(1, 1), node); - if(cnode == -1) return 0; - return (int)cnode; + if (node == -1) + return 0; + cnode = prom_node_to_node("parent", node); + if (cnode == -1) + return 0; + return cnode; } /* Return the next sibling of node 'node' or zero if no more siblings @@ -50,7 +69,7 @@ inline int prom_getparent(int node) */ inline int __prom_getsibling(int node) { - return p1275_cmd(prom_peer_name, P1275_INOUT(1, 1), node); + return prom_node_to_node(prom_peer_name, node); } inline int prom_getsibling(int node) @@ -72,11 +91,21 @@ EXPORT_SYMBOL(prom_getsibling); */ inline int prom_getproplen(int node, const char *prop) { - if((!node) || (!prop)) return -1; - return p1275_cmd ("getproplen", - P1275_ARG(1,P1275_ARG_IN_STRING)| - P1275_INOUT(2, 1), - node, prop); + unsigned long args[6]; + + if (!node || !prop) + return -1; + + args[0] = (unsigned long) "getproplen"; + args[1] = 2; + args[2] = 1; + args[3] = (unsigned int) node; + args[4] = (unsigned long) prop; + args[5] = (unsigned long) -1; + + p1275_cmd_direct(args); + + return (int) args[5]; } EXPORT_SYMBOL(prom_getproplen); @@ -87,19 +116,25 @@ EXPORT_SYMBOL(prom_getproplen); inline int prom_getproperty(int node, const char *prop, char *buffer, int bufsize) { + unsigned long args[8]; int plen; plen = prom_getproplen(node, prop); - if ((plen > bufsize) || (plen == 0) || (plen == -1)) { + if ((plen > bufsize) || (plen == 0) || (plen == -1)) return -1; - } else { - /* Ok, things seem all right. */ - return p1275_cmd(prom_getprop_name, - P1275_ARG(1,P1275_ARG_IN_STRING)| - P1275_ARG(2,P1275_ARG_OUT_BUF)| - P1275_INOUT(4, 1), - node, prop, buffer, P1275_SIZE(plen)); - } + + args[0] = (unsigned long) prom_getprop_name; + args[1] = 4; + args[2] = 1; + args[3] = (unsigned int) node; + args[4] = (unsigned long) prop; + args[5] = (unsigned long) buffer; + args[6] = bufsize; + args[7] = (unsigned long) -1; + + p1275_cmd_direct(args); + + return (int) args[7]; } EXPORT_SYMBOL(prom_getproperty); @@ -110,7 +145,7 @@ inline int prom_getint(int node, const char *prop) { int intprop; - if(prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1) + if (prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1) return intprop; return -1; @@ -126,7 +161,8 @@ int prom_getintdefault(int node, const char *property, int deflt) int retval; retval = prom_getint(node, property); - if(retval == -1) return deflt; + if (retval == -1) + return deflt; return retval; } @@ -138,7 +174,8 @@ int prom_getbool(int node, const char *prop) int retval; retval = prom_getproplen(node, prop); - if(retval == -1) return 0; + if (retval == -1) + return 0; return 1; } EXPORT_SYMBOL(prom_getbool); @@ -152,7 +189,8 @@ void prom_getstring(int node, const char *prop, char *user_buf, int ubuf_size) int len; len = prom_getproperty(node, prop, user_buf, ubuf_size); - if(len != -1) return; + if (len != -1) + return; user_buf[0] = 0; } EXPORT_SYMBOL(prom_getstring); @@ -164,7 +202,8 @@ int prom_nodematch(int node, const char *name) { char namebuf[128]; prom_getproperty(node, "name", namebuf, sizeof(namebuf)); - if(strcmp(namebuf, name) == 0) return 1; + if (strcmp(namebuf, name) == 0) + return 1; return 0; } @@ -190,16 +229,29 @@ int prom_searchsiblings(int node_start, const char *nodename) } EXPORT_SYMBOL(prom_searchsiblings); +static const char *prom_nextprop_name = "nextprop"; + /* Return the first property type for node 'node'. * buffer should be at least 32B in length */ inline char *prom_firstprop(int node, char *buffer) { + unsigned long args[7]; + *buffer = 0; - if(node == -1) return buffer; - p1275_cmd ("nextprop", P1275_ARG(2,P1275_ARG_OUT_32B)| - P1275_INOUT(3, 0), - node, (char *) 0x0, buffer); + if (node == -1) + return buffer; + + args[0] = (unsigned long) prom_nextprop_name; + args[1] = 3; + args[2] = 1; + args[3] = (unsigned int) node; + args[4] = 0; + args[5] = (unsigned long) buffer; + args[6] = (unsigned long) -1; + + p1275_cmd_direct(args); + return buffer; } EXPORT_SYMBOL(prom_firstprop); @@ -210,9 +262,10 @@ EXPORT_SYMBOL(prom_firstprop); */ inline char *prom_nextprop(int node, const char *oprop, char *buffer) { + unsigned long args[7]; char buf[32]; - if(node == -1) { + if (node == -1) { *buffer = 0; return buffer; } @@ -220,10 +273,17 @@ inline char *prom_nextprop(int node, const char *oprop, char *buffer) strcpy (buf, oprop); oprop = buf; } - p1275_cmd ("nextprop", P1275_ARG(1,P1275_ARG_IN_STRING)| - P1275_ARG(2,P1275_ARG_OUT_32B)| - P1275_INOUT(3, 0), - node, oprop, buffer); + + args[0] = (unsigned long) prom_nextprop_name; + args[1] = 3; + args[2] = 1; + args[3] = (unsigned int) node; + args[4] = (unsigned long) oprop; + args[5] = (unsigned long) buffer; + args[6] = (unsigned long) -1; + + p1275_cmd_direct(args); + return buffer; } EXPORT_SYMBOL(prom_nextprop); @@ -231,12 +291,19 @@ EXPORT_SYMBOL(prom_nextprop); int prom_finddevice(const char *name) { + unsigned long args[5]; + if (!name) return 0; - return p1275_cmd(prom_finddev_name, - P1275_ARG(0,P1275_ARG_IN_STRING)| - P1275_INOUT(1, 1), - name); + args[0] = (unsigned long) "finddevice"; + args[1] = 1; + args[2] = 1; + args[3] = (unsigned long) name; + args[4] = (unsigned long) -1; + + p1275_cmd_direct(args); + + return (int) args[4]; } EXPORT_SYMBOL(prom_finddevice); @@ -247,7 +314,7 @@ int prom_node_has_property(int node, const char *prop) *buf = 0; do { prom_nextprop(node, buf, buf); - if(!strcmp(buf, prop)) + if (!strcmp(buf, prop)) return 1; } while (*buf); return 0; @@ -260,6 +327,8 @@ EXPORT_SYMBOL(prom_node_has_property); int prom_setprop(int node, const char *pname, char *value, int size) { + unsigned long args[8]; + if (size == 0) return 0; if ((pname == 0) || (value == 0)) @@ -271,19 +340,37 @@ prom_setprop(int node, const char *pname, char *value, int size) return 0; } #endif - return p1275_cmd ("setprop", P1275_ARG(1,P1275_ARG_IN_STRING)| - P1275_ARG(2,P1275_ARG_IN_BUF)| - P1275_INOUT(4, 1), - node, pname, value, P1275_SIZE(size)); + args[0] = (unsigned long) "setprop"; + args[1] = 4; + args[2] = 1; + args[3] = (unsigned int) node; + args[4] = (unsigned long) pname; + args[5] = (unsigned long) value; + args[6] = size; + args[7] = (unsigned long) -1; + + p1275_cmd_direct(args); + + return (int) args[7]; } EXPORT_SYMBOL(prom_setprop); inline int prom_inst2pkg(int inst) { + unsigned long args[5]; int node; - node = p1275_cmd ("instance-to-package", P1275_INOUT(1, 1), inst); - if (node == -1) return 0; + args[0] = (unsigned long) "instance-to-package"; + args[1] = 1; + args[2] = 1; + args[3] = (unsigned int) inst; + args[4] = (unsigned long) -1; + + p1275_cmd_direct(args); + + node = (int) args[4]; + if (node == -1) + return 0; return node; } @@ -296,17 +383,28 @@ prom_pathtoinode(const char *path) int node, inst; inst = prom_devopen (path); - if (inst == 0) return 0; - node = prom_inst2pkg (inst); - prom_devclose (inst); - if (node == -1) return 0; + if (inst == 0) + return 0; + node = prom_inst2pkg(inst); + prom_devclose(inst); + if (node == -1) + return 0; return node; } int prom_ihandle2path(int handle, char *buffer, int bufsize) { - return p1275_cmd("instance-to-path", - P1275_ARG(1,P1275_ARG_OUT_BUF)| - P1275_INOUT(3, 1), - handle, buffer, P1275_SIZE(bufsize)); + unsigned long args[7]; + + args[0] = (unsigned long) "instance-to-path"; + args[1] = 3; + args[2] = 1; + args[3] = (unsigned int) handle; + args[4] = (unsigned long) buffer; + args[5] = bufsize; + args[6] = (unsigned long) -1; + + p1275_cmd_direct(args); + + return (int) args[6]; } -- cgit v0.10.2 From 7af048dc7639db5202c56fecf2346c310647a218 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 24 Aug 2010 09:26:20 +0200 Subject: [S390] s390: fix build error (sys_execve) fix this build error: arch/s390/kernel/process.c:272: error: conflicting types for 'sys_execve' arch/s390/kernel/entry.h:45: error: previous declaration of 'sys_execve' was here make[1]: *** [arch/s390/kernel/process.o] Error 1 make: *** [arch/s390/kernel] Error 2 introduced by d7627467b7a8dd6944885290a03a07ceb28c10eb Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h index 403fb43..ff579b6 100644 --- a/arch/s390/kernel/entry.h +++ b/arch/s390/kernel/entry.h @@ -42,8 +42,8 @@ long sys_clone(unsigned long newsp, unsigned long clone_flags, int __user *parent_tidptr, int __user *child_tidptr); long sys_vfork(void); void execve_tail(void); -long sys_execve(const char __user *name, char __user * __user *argv, - char __user * __user *envp); +long sys_execve(const char __user *name, const char __user *const __user *argv, + const char __user *const __user *envp); long sys_sigsuspend(int history0, int history1, old_sigset_t mask); long sys_sigaction(int sig, const struct old_sigaction __user *act, struct old_sigaction __user *oact); -- cgit v0.10.2 From 050eef364ad700590a605a0749f825cab4834b1e Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Tue, 24 Aug 2010 09:26:21 +0200 Subject: [S390] fix tlb flushing vs. concurrent /proc accesses The tlb flushing code uses the mm_users field of the mm_struct to decide if each page table entry needs to be flushed individually with IPTE or if a global flush for the mm_struct is sufficient after all page table updates have been done. The comment for mm_users says "How many users with user space?" but the /proc code increases mm_users after it found the process structure by pid without creating a new user process. Which makes mm_users useless for the decision between the two tlb flusing methods. The current code can be confused to not flush tlb entries by a concurrent access to /proc files if e.g. a fork is in progres. The solution for this problem is to make the tlb flushing logic independent from the mm_users field. Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/include/asm/hugetlb.h b/arch/s390/include/asm/hugetlb.h index 670a1d1..bb8343d 100644 --- a/arch/s390/include/asm/hugetlb.h +++ b/arch/s390/include/asm/hugetlb.h @@ -97,6 +97,7 @@ static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm, { pte_t pte = huge_ptep_get(ptep); + mm->context.flush_mm = 1; pmd_clear((pmd_t *) ptep); return pte; } @@ -167,7 +168,8 @@ static inline void huge_ptep_invalidate(struct mm_struct *mm, ({ \ pte_t __pte = huge_ptep_get(__ptep); \ if (pte_write(__pte)) { \ - if (atomic_read(&(__mm)->mm_users) > 1 || \ + (__mm)->context.flush_mm = 1; \ + if (atomic_read(&(__mm)->context.attach_count) > 1 || \ (__mm) != current->active_mm) \ huge_ptep_invalidate(__mm, __addr, __ptep); \ set_huge_pte_at(__mm, __addr, __ptep, \ diff --git a/arch/s390/include/asm/mmu.h b/arch/s390/include/asm/mmu.h index 99e3409..78522cde 100644 --- a/arch/s390/include/asm/mmu.h +++ b/arch/s390/include/asm/mmu.h @@ -2,6 +2,8 @@ #define __MMU_H typedef struct { + atomic_t attach_count; + unsigned int flush_mm; spinlock_t list_lock; struct list_head crst_list; struct list_head pgtable_list; diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h index 976e273..a6f0e7c 100644 --- a/arch/s390/include/asm/mmu_context.h +++ b/arch/s390/include/asm/mmu_context.h @@ -11,11 +11,14 @@ #include #include +#include #include static inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm) { + atomic_set(&mm->context.attach_count, 0); + mm->context.flush_mm = 0; mm->context.asce_bits = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS; #ifdef CONFIG_64BIT mm->context.asce_bits |= _ASCE_TYPE_REGION3; @@ -76,6 +79,12 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, { cpumask_set_cpu(smp_processor_id(), mm_cpumask(next)); update_mm(next, tsk); + atomic_dec(&prev->context.attach_count); + WARN_ON(atomic_read(&prev->context.attach_count) < 0); + atomic_inc(&next->context.attach_count); + /* Check for TLBs not flushed yet */ + if (next->context.flush_mm) + __tlb_flush_mm(next); } #define enter_lazy_tlb(mm,tsk) do { } while (0) diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 89a504c..3157441 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h @@ -880,7 +880,8 @@ static inline void ptep_invalidate(struct mm_struct *mm, #define ptep_get_and_clear(__mm, __address, __ptep) \ ({ \ pte_t __pte = *(__ptep); \ - if (atomic_read(&(__mm)->mm_users) > 1 || \ + (__mm)->context.flush_mm = 1; \ + if (atomic_read(&(__mm)->context.attach_count) > 1 || \ (__mm) != current->active_mm) \ ptep_invalidate(__mm, __address, __ptep); \ else \ @@ -923,7 +924,8 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, ({ \ pte_t __pte = *(__ptep); \ if (pte_write(__pte)) { \ - if (atomic_read(&(__mm)->mm_users) > 1 || \ + (__mm)->context.flush_mm = 1; \ + if (atomic_read(&(__mm)->context.attach_count) > 1 || \ (__mm) != current->active_mm) \ ptep_invalidate(__mm, __addr, __ptep); \ set_pte_at(__mm, __addr, __ptep, pte_wrprotect(__pte)); \ diff --git a/arch/s390/include/asm/tlb.h b/arch/s390/include/asm/tlb.h index 81150b0..fd1c00d 100644 --- a/arch/s390/include/asm/tlb.h +++ b/arch/s390/include/asm/tlb.h @@ -50,8 +50,7 @@ static inline struct mmu_gather *tlb_gather_mmu(struct mm_struct *mm, struct mmu_gather *tlb = &get_cpu_var(mmu_gathers); tlb->mm = mm; - tlb->fullmm = full_mm_flush || (num_online_cpus() == 1) || - (atomic_read(&mm->mm_users) <= 1 && mm == current->active_mm); + tlb->fullmm = full_mm_flush; tlb->nr_ptes = 0; tlb->nr_pxds = TLB_NR_PTRS; if (tlb->fullmm) diff --git a/arch/s390/include/asm/tlbflush.h b/arch/s390/include/asm/tlbflush.h index 304cffa..29d5d6d 100644 --- a/arch/s390/include/asm/tlbflush.h +++ b/arch/s390/include/asm/tlbflush.h @@ -94,8 +94,12 @@ static inline void __tlb_flush_mm(struct mm_struct * mm) static inline void __tlb_flush_mm_cond(struct mm_struct * mm) { - if (atomic_read(&mm->mm_users) <= 1 && mm == current->active_mm) + spin_lock(&mm->page_table_lock); + if (mm->context.flush_mm) { __tlb_flush_mm(mm); + mm->context.flush_mm = 0; + } + spin_unlock(&mm->page_table_lock); } /* diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 541053e..8127ebd 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -583,6 +583,7 @@ int __cpuinit __cpu_up(unsigned int cpu) sf->gprs[9] = (unsigned long) sf; cpu_lowcore->save_area[15] = (unsigned long) sf; __ctl_store(cpu_lowcore->cregs_save_area, 0, 15); + atomic_inc(&init_mm.context.attach_count); asm volatile( " stam 0,15,0(%0)" : : "a" (&cpu_lowcore->access_regs_save_area) : "memory"); @@ -659,6 +660,7 @@ void __cpu_die(unsigned int cpu) while (sigp_p(0, cpu, sigp_set_prefix) == sigp_busy) udelay(10); smp_free_lowcore(cpu); + atomic_dec(&init_mm.context.attach_count); pr_info("Processor %d stopped\n", cpu); } diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index acc91c7..30eb6d02 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -74,6 +74,8 @@ void __init paging_init(void) __ctl_load(S390_lowcore.kernel_asce, 13, 13); __raw_local_irq_ssm(ssm_mask); + atomic_set(&init_mm.context.attach_count, 1); + sparse_memory_present_with_active_regions(MAX_NUMNODES); sparse_init(); memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); -- cgit v0.10.2 From 577ba406e1cceac4776b095c83ee2896074a0327 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Tue, 24 Aug 2010 10:41:33 +0200 Subject: V4L/DVB: mantis: Fix IR_CORE dependency This build bug triggers: drivers/built-in.o: In function `mantis_exit': (.text+0x377413): undefined reference to `ir_input_unregister' drivers/built-in.o: In function `mantis_input_init': (.text+0x3774ff): undefined reference to `__ir_input_register' If MANTIS_CORE is enabled but IR_CORE is not. Add the correct dependency. Signed-off-by: Ingo Molnar Acked-by: Randy Dunlap Signed-off-by: Linus Torvalds diff --git a/drivers/media/dvb/mantis/Kconfig b/drivers/media/dvb/mantis/Kconfig index decdeda..fd0830e 100644 --- a/drivers/media/dvb/mantis/Kconfig +++ b/drivers/media/dvb/mantis/Kconfig @@ -1,6 +1,6 @@ config MANTIS_CORE tristate "Mantis/Hopper PCI bridge based devices" - depends on PCI && I2C && INPUT + depends on PCI && I2C && INPUT && IR_CORE help Support for PCI cards based on the Mantis and Hopper PCi bridge. -- cgit v0.10.2 From a9728c9a31524ef927260096411ee85c8ee6b163 Mon Sep 17 00:00:00 2001 From: Ossama Othman Date: Tue, 24 Aug 2010 12:55:14 +0100 Subject: rar: Fix off by one error It looks like there is an off-by-one error in one of your changes to drivers/staging/rar_register/rar_register.c: Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds diff --git a/drivers/platform/x86/intel_rar_register.c b/drivers/platform/x86/intel_rar_register.c index 73f8e6d..2b11a333 100644 --- a/drivers/platform/x86/intel_rar_register.c +++ b/drivers/platform/x86/intel_rar_register.c @@ -145,7 +145,7 @@ static void free_rar_device(struct rar_device *rar) */ static struct rar_device *_rar_to_device(int rar, int *off) { - if (rar >= 0 && rar <= 3) { + if (rar >= 0 && rar < MRST_NUM_RAR) { *off = rar; return &my_rar_device; } -- cgit v0.10.2 From 32e2f63bcc8903487975506d8db5931a8c4bbb1f Mon Sep 17 00:00:00 2001 From: Jianwei Yang Date: Tue, 24 Aug 2010 14:32:38 +0100 Subject: intel_scu_ipc: fix IPC i2c write bug We should pass the data to the data register. Signed-off-by: Jianwei Yang Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index 943f908..6abe18e 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -487,7 +487,7 @@ int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data) mdelay(1); *data = readl(ipcdev.i2c_base + I2C_DATA_ADDR); } else if (cmd == IPC_I2C_WRITE) { - writel(addr, ipcdev.i2c_base + I2C_DATA_ADDR); + writel(*data, ipcdev.i2c_base + I2C_DATA_ADDR); mdelay(1); writel(addr, ipcdev.i2c_base + IPC_I2C_CNTRL_ADDR); } else { -- cgit v0.10.2 From 9559fcdbff4f93d29af04478bbc48294519424f5 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 24 Aug 2010 11:31:16 -0700 Subject: drm/i915: fix vblank wait test condition When converting this to the new wait_for macro I inverted the wait condition, which causes all sorts of problems. So correct it to fix several failures caused by the bad wait (flickering, bad output detection, tearing, etc.). Reviewed-by: Chris Wilson Tested-by: Sitsofe Wheeler Signed-off-by: Jesse Barnes Signed-off-by: Linus Torvalds diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 23157e1..11a3394 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -992,7 +992,7 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe) /* Wait for vblank interrupt bit to set */ if (wait_for((I915_READ(pipestat_reg) & - PIPE_VBLANK_INTERRUPT_STATUS) == 0, + PIPE_VBLANK_INTERRUPT_STATUS), 50, 0)) DRM_DEBUG_KMS("vblank wait timed out\n"); } -- cgit v0.10.2 From 8ca3eb08097f6839b2206e2242db4179aee3cfb3 Mon Sep 17 00:00:00 2001 From: "Luck, Tony" Date: Tue, 24 Aug 2010 11:44:18 -0700 Subject: guard page for stacks that grow upwards pa-risc and ia64 have stacks that grow upwards. Check that they do not run into other mappings. By making VM_GROWSUP 0x0 on architectures that do not ever use it, we can avoid some unpleasant #ifdefs in check_stack_guard_page(). Signed-off-by: Tony Luck Signed-off-by: Linus Torvalds diff --git a/include/linux/mm.h b/include/linux/mm.h index 709f672..831c693 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -78,7 +78,11 @@ extern unsigned int kobjsize(const void *objp); #define VM_MAYSHARE 0x00000080 #define VM_GROWSDOWN 0x00000100 /* general info on the segment */ +#if defined(CONFIG_STACK_GROWSUP) || defined(CONFIG_IA64) #define VM_GROWSUP 0x00000200 +#else +#define VM_GROWSUP 0x00000000 +#endif #define VM_PFNMAP 0x00000400 /* Page-ranges managed without "struct page", just pure PFN */ #define VM_DENYWRITE 0x00000800 /* ETXTBSY on write attempts.. */ @@ -1330,8 +1334,10 @@ unsigned long ra_submit(struct file_ra_state *ra, /* Do stack extension */ extern int expand_stack(struct vm_area_struct *vma, unsigned long address); -#ifdef CONFIG_IA64 +#if VM_GROWSUP extern int expand_upwards(struct vm_area_struct *vma, unsigned long address); +#else + #define expand_upwards(vma, address) do { } while (0) #endif extern int expand_stack_downwards(struct vm_area_struct *vma, unsigned long address); diff --git a/mm/memory.c b/mm/memory.c index 2ed2267..6b2ab10 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2760,11 +2760,9 @@ out_release: } /* - * This is like a special single-page "expand_downwards()", - * except we must first make sure that 'address-PAGE_SIZE' + * This is like a special single-page "expand_{down|up}wards()", + * except we must first make sure that 'address{-|+}PAGE_SIZE' * doesn't hit another vma. - * - * The "find_vma()" will do the right thing even if we wrap */ static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned long address) { @@ -2783,6 +2781,15 @@ static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned lo expand_stack(vma, address - PAGE_SIZE); } + if ((vma->vm_flags & VM_GROWSUP) && address + PAGE_SIZE == vma->vm_end) { + struct vm_area_struct *next = vma->vm_next; + + /* As VM_GROWSDOWN but s/below/above/ */ + if (next && next->vm_start == address + PAGE_SIZE) + return next->vm_flags & VM_GROWSUP ? 0 : -ENOMEM; + + expand_upwards(vma, address + PAGE_SIZE); + } return 0; } diff --git a/mm/mmap.c b/mm/mmap.c index 331e51a..6128dc8 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1716,9 +1716,6 @@ static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, uns * PA-RISC uses this for its stack; IA64 for its Register Backing Store. * vma is the last one with address > vma->vm_end. Have to extend vma. */ -#ifndef CONFIG_IA64 -static -#endif int expand_upwards(struct vm_area_struct *vma, unsigned long address) { int error; -- cgit v0.10.2