aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2011-07-13 16:01:46 -0400
committerKeith Packard <keithp@keithp.com>2011-07-13 16:35:34 -0400
commit99834ea446d5c0da3f6cfa355fe4670840d45f79 (patch)
treee3c8db257a2fe402477399a892c710989a1bd15f /drivers/gpu
parent95736720fc866eadb2ce1789631b907c0f38cb7c (diff)
drm/i915/bios: Avoid temporary allocation whilst searching for downclock
Alan Cox reported a missing check on the kmalloc return value for the allocation of a temporary mode used for searching for the LVDS downlock frequency. This allocation is roughly 200 bytes, a little too large to friviously place on the stack. However, we can simply use the few bytes we need stored within the original DVO timing data, skip the translation and do the compare directly between the timing data rather than on a mode, thus avoiding the need for any temporary allocations. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Cc: Keith Packard <keithp@keithp.com> Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c142
1 files changed, 83 insertions, 59 deletions
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index 927442a11925..61abef8a8119 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -74,7 +74,7 @@ get_blocksize(void *p)
74 74
75static void 75static void
76fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, 76fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode,
77 struct lvds_dvo_timing *dvo_timing) 77 const struct lvds_dvo_timing *dvo_timing)
78{ 78{
79 panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) | 79 panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) |
80 dvo_timing->hactive_lo; 80 dvo_timing->hactive_lo;
@@ -115,20 +115,75 @@ fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode,
115 drm_mode_set_name(panel_fixed_mode); 115 drm_mode_set_name(panel_fixed_mode);
116} 116}
117 117
118static bool
119lvds_dvo_timing_equal_size(const struct lvds_dvo_timing *a,
120 const struct lvds_dvo_timing *b)
121{
122 if (a->hactive_hi != b->hactive_hi ||
123 a->hactive_lo != b->hactive_lo)
124 return false;
125
126 if (a->hsync_off_hi != b->hsync_off_hi ||
127 a->hsync_off_lo != b->hsync_off_lo)
128 return false;
129
130 if (a->hsync_pulse_width != b->hsync_pulse_width)
131 return false;
132
133 if (a->hblank_hi != b->hblank_hi ||
134 a->hblank_lo != b->hblank_lo)
135 return false;
136
137 if (a->vactive_hi != b->vactive_hi ||
138 a->vactive_lo != b->vactive_lo)
139 return false;
140
141 if (a->vsync_off != b->vsync_off)
142 return false;
143
144 if (a->vsync_pulse_width != b->vsync_pulse_width)
145 return false;
146
147 if (a->vblank_hi != b->vblank_hi ||
148 a->vblank_lo != b->vblank_lo)
149 return false;
150
151 return true;
152}
153
154static const struct lvds_dvo_timing *
155get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *lvds_lfp_data,
156 const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs,
157 int index)
158{
159 /*
160 * the size of fp_timing varies on the different platform.
161 * So calculate the DVO timing relative offset in LVDS data
162 * entry to get the DVO timing entry
163 */
164
165 int lfp_data_size =
166 lvds_lfp_data_ptrs->ptr[1].dvo_timing_offset -
167 lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset;
168 int dvo_timing_offset =
169 lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset -
170 lvds_lfp_data_ptrs->ptr[0].fp_timing_offset;
171 char *entry = (char *)lvds_lfp_data->data + lfp_data_size * index;
172
173 return (struct lvds_dvo_timing *)(entry + dvo_timing_offset);
174}
175
118/* Try to find integrated panel data */ 176/* Try to find integrated panel data */
119static void 177static void
120parse_lfp_panel_data(struct drm_i915_private *dev_priv, 178parse_lfp_panel_data(struct drm_i915_private *dev_priv,
121 struct bdb_header *bdb) 179 struct bdb_header *bdb)
122{ 180{
123 struct bdb_lvds_options *lvds_options; 181 const struct bdb_lvds_options *lvds_options;
124 struct bdb_lvds_lfp_data *lvds_lfp_data; 182 const struct bdb_lvds_lfp_data *lvds_lfp_data;
125 struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs; 183 const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs;
126 struct bdb_lvds_lfp_data_entry *entry; 184 const struct lvds_dvo_timing *panel_dvo_timing;
127 struct lvds_dvo_timing *dvo_timing;
128 struct drm_display_mode *panel_fixed_mode; 185 struct drm_display_mode *panel_fixed_mode;
129 int lfp_data_size, dvo_timing_offset; 186 int i, downclock;
130 int i, temp_downclock;
131 struct drm_display_mode *temp_mode;
132 187
133 lvds_options = find_section(bdb, BDB_LVDS_OPTIONS); 188 lvds_options = find_section(bdb, BDB_LVDS_OPTIONS);
134 if (!lvds_options) 189 if (!lvds_options)
@@ -150,75 +205,44 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
150 205
151 dev_priv->lvds_vbt = 1; 206 dev_priv->lvds_vbt = 1;
152 207
153 lfp_data_size = lvds_lfp_data_ptrs->ptr[1].dvo_timing_offset - 208 panel_dvo_timing = get_lvds_dvo_timing(lvds_lfp_data,
154 lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset; 209 lvds_lfp_data_ptrs,
155 entry = (struct bdb_lvds_lfp_data_entry *) 210 lvds_options->panel_type);
156 ((uint8_t *)lvds_lfp_data->data + (lfp_data_size *
157 lvds_options->panel_type));
158 dvo_timing_offset = lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset -
159 lvds_lfp_data_ptrs->ptr[0].fp_timing_offset;
160
161 /*
162 * the size of fp_timing varies on the different platform.
163 * So calculate the DVO timing relative offset in LVDS data
164 * entry to get the DVO timing entry
165 */
166 dvo_timing = (struct lvds_dvo_timing *)
167 ((unsigned char *)entry + dvo_timing_offset);
168 211
169 panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); 212 panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL);
170 if (!panel_fixed_mode) 213 if (!panel_fixed_mode)
171 return; 214 return;
172 215
173 fill_detail_timing_data(panel_fixed_mode, dvo_timing); 216 fill_detail_timing_data(panel_fixed_mode, panel_dvo_timing);
174 217
175 dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode; 218 dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode;
176 219
177 DRM_DEBUG_KMS("Found panel mode in BIOS VBT tables:\n"); 220 DRM_DEBUG_KMS("Found panel mode in BIOS VBT tables:\n");
178 drm_mode_debug_printmodeline(panel_fixed_mode); 221 drm_mode_debug_printmodeline(panel_fixed_mode);
179 222
180 temp_mode = kzalloc(sizeof(*temp_mode), GFP_KERNEL);
181 temp_downclock = panel_fixed_mode->clock;
182 /* 223 /*
183 * enumerate the LVDS panel timing info entry in VBT to check whether 224 * Iterate over the LVDS panel timing info to find the lowest clock
184 * the LVDS downclock is found. 225 * for the native resolution.
185 */ 226 */
227 downclock = panel_dvo_timing->clock;
186 for (i = 0; i < 16; i++) { 228 for (i = 0; i < 16; i++) {
187 entry = (struct bdb_lvds_lfp_data_entry *) 229 const struct lvds_dvo_timing *dvo_timing;
188 ((uint8_t *)lvds_lfp_data->data + (lfp_data_size * i)); 230
189 dvo_timing = (struct lvds_dvo_timing *) 231 dvo_timing = get_lvds_dvo_timing(lvds_lfp_data,
190 ((unsigned char *)entry + dvo_timing_offset); 232 lvds_lfp_data_ptrs,
191 233 i);
192 fill_detail_timing_data(temp_mode, dvo_timing); 234 if (lvds_dvo_timing_equal_size(dvo_timing, panel_dvo_timing) &&
193 235 dvo_timing->clock < downclock)
194 if (temp_mode->hdisplay == panel_fixed_mode->hdisplay && 236 downclock = dvo_timing->clock;
195 temp_mode->hsync_start == panel_fixed_mode->hsync_start &&
196 temp_mode->hsync_end == panel_fixed_mode->hsync_end &&
197 temp_mode->htotal == panel_fixed_mode->htotal &&
198 temp_mode->vdisplay == panel_fixed_mode->vdisplay &&
199 temp_mode->vsync_start == panel_fixed_mode->vsync_start &&
200 temp_mode->vsync_end == panel_fixed_mode->vsync_end &&
201 temp_mode->vtotal == panel_fixed_mode->vtotal &&
202 temp_mode->clock < temp_downclock) {
203 /*
204 * downclock is already found. But we expect
205 * to find the lower downclock.
206 */
207 temp_downclock = temp_mode->clock;
208 }
209 /* clear it to zero */
210 memset(temp_mode, 0, sizeof(*temp_mode));
211 } 237 }
212 kfree(temp_mode); 238
213 if (temp_downclock < panel_fixed_mode->clock && 239 if (downclock < panel_dvo_timing->clock && i915_lvds_downclock) {
214 i915_lvds_downclock) {
215 dev_priv->lvds_downclock_avail = 1; 240 dev_priv->lvds_downclock_avail = 1;
216 dev_priv->lvds_downclock = temp_downclock; 241 dev_priv->lvds_downclock = downclock * 10;
217 DRM_DEBUG_KMS("LVDS downclock is found in VBT. " 242 DRM_DEBUG_KMS("LVDS downclock is found in VBT. "
218 "Normal Clock %dKHz, downclock %dKHz\n", 243 "Normal Clock %dKHz, downclock %dKHz\n",
219 temp_downclock, panel_fixed_mode->clock); 244 panel_fixed_mode->clock, 10*downclock);
220 } 245 }
221 return;
222} 246}
223 247
224/* Try to find sdvo panel data */ 248/* Try to find sdvo panel data */