[Intel-gfx] [PATCHv4] drm/i915/display/dp: On AUX xfer timeout restart freshly
kernel test robot
lkp at intel.com
Mon Jun 19 11:08:09 UTC 2023
Hi Arun,
kernel test robot noticed the following build warnings:
[auto build test WARNING on drm-tip/drm-tip]
url: https://github.com/intel-lab-lkp/linux/commits/Arun-R-Murthy/drm-i915-display-dp-On-AUX-xfer-timeout-restart-freshly/20230619-163622
base: git://anongit.freedesktop.org/drm/drm-tip drm-tip
patch link: https://lore.kernel.org/r/20230619082715.922094-1-arun.r.murthy%40intel.com
patch subject: [Intel-gfx] [PATCHv4] drm/i915/display/dp: On AUX xfer timeout restart freshly
config: x86_64-rhel-8.3-rust (https://download.01.org/0day-ci/archive/20230619/202306191845.yMTzbDgG-lkp@intel.com/config)
compiler: clang version 15.0.7 (https://github.com/llvm/llvm-project.git 8dfdcc7b7bf66834a761bd8de445840ef68e4d1a)
reproduce: (https://download.01.org/0day-ci/archive/20230619/202306191845.yMTzbDgG-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202306191845.yMTzbDgG-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/gpu/drm/i915/display/intel_dp_aux.c:284:12: warning: variable 'aux_clock_divider' is uninitialized when used here [-Wuninitialized]
aux_clock_divider);
^~~~~~~~~~~~~~~~~
drivers/gpu/drm/i915/display/intel_dp_aux.c:222:23: note: initialize the variable 'aux_clock_divider' to silence this warning
u32 aux_clock_divider;
^
= 0
1 warning generated.
vim +/aux_clock_divider +284 drivers/gpu/drm/i915/display/intel_dp_aux.c
209
210 static int
211 intel_dp_aux_xfer(struct intel_dp *intel_dp,
212 const u8 *send, int send_bytes,
213 u8 *recv, int recv_size,
214 u32 aux_send_ctl_flags)
215 {
216 struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
217 struct drm_i915_private *i915 =
218 to_i915(dig_port->base.base.dev);
219 enum phy phy = intel_port_to_phy(i915, dig_port->base.port);
220 bool is_tc_port = intel_phy_is_tc(i915, phy);
221 i915_reg_t ch_ctl, ch_data[5];
222 u32 aux_clock_divider;
223 enum intel_display_power_domain aux_domain;
224 intel_wakeref_t aux_wakeref;
225 intel_wakeref_t pps_wakeref;
226 int i, ret, recv_bytes;
227 int try, clock = 0;
228 u32 status;
229 u32 send_ctl;
230 bool vdd;
231
232 ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp);
233 for (i = 0; i < ARRAY_SIZE(ch_data); i++)
234 ch_data[i] = intel_dp->aux_ch_data_reg(intel_dp, i);
235
236 if (is_tc_port) {
237 intel_tc_port_lock(dig_port);
238 /*
239 * Abort transfers on a disconnected port as required by
240 * DP 1.4a link CTS 4.2.1.5, also avoiding the long AUX
241 * timeouts that would otherwise happen.
242 * TODO: abort the transfer on non-TC ports as well.
243 */
244 if (!intel_tc_port_connected_locked(&dig_port->base)) {
245 ret = -ENXIO;
246 goto out_unlock;
247 }
248 }
249
250 aux_domain = intel_aux_power_domain(dig_port);
251
252 aux_wakeref = intel_display_power_get(i915, aux_domain);
253 pps_wakeref = intel_pps_lock(intel_dp);
254
255 /*
256 * We will be called with VDD already enabled for dpcd/edid/oui reads.
257 * In such cases we want to leave VDD enabled and it's up to upper layers
258 * to turn it off. But for eg. i2c-dev access we need to turn it on/off
259 * ourselves.
260 */
261 vdd = intel_pps_vdd_on_unlocked(intel_dp);
262
263 /*
264 * dp aux is extremely sensitive to irq latency, hence request the
265 * lowest possible wakeup latency and so prevent the cpu from going into
266 * deep sleep states.
267 */
268 cpu_latency_qos_update_request(&intel_dp->pm_qos, 0);
269
270 intel_pps_check_power_unlocked(intel_dp);
271
272 /*
273 * FIXME PSR should be disabled here to prevent
274 * it using the same AUX CH simultaneously
275 */
276
277 /* Only 5 data registers! */
278 if (drm_WARN_ON(&i915->drm, send_bytes > 20 || recv_size > 20)) {
279 ret = -E2BIG;
280 goto out;
281 }
282 send_ctl = intel_dp->get_aux_send_ctl(intel_dp,
283 send_bytes,
> 284 aux_clock_divider);
285 send_ctl |= aux_send_ctl_flags;
286
287 while ((aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, clock++))) {
288 /* Re-visit : Must try at least 3 times according to DP spec */
289 for (try = 0; try < 5; try++) {
290 /* Try to wait for any previous AUX channel activity */
291 status = intel_dp_aux_wait_done(intel_dp);
292 /* just trace the final value */
293 trace_i915_reg_rw(false, ch_ctl, status, sizeof(status), true);
294
295 if (status & DP_AUX_CH_CTL_SEND_BUSY) {
296 drm_WARN(&i915->drm, 1,
297 "%s: not started, previous Tx still in process (status 0x%08x)\n",
298 intel_dp->aux.name, status);
299 intel_dp->aux_busy_last_status = status;
300 if (try > 3) {
301 ret = -EBUSY;
302 goto out;
303 } else
304 continue;
305 }
306
307 /* Load the send data into the aux channel data registers */
308 for (i = 0; i < send_bytes; i += 4)
309 intel_de_write(i915, ch_data[i >> 2],
310 intel_dp_aux_pack(send + i,
311 send_bytes - i));
312
313 /* Send the command and wait for it to complete */
314 intel_de_write(i915, ch_ctl, send_ctl);
315
316 /* TODO: if typeC then 4.2ms else 800us. For DG2 add 1.5ms for both cases */
317 status = intel_dp_aux_wait_done(intel_dp);
318
319 /* Clear done status and any errors */
320 intel_de_write(i915, ch_ctl,
321 status | DP_AUX_CH_CTL_DONE |
322 DP_AUX_CH_CTL_TIME_OUT_ERROR |
323 DP_AUX_CH_CTL_RECEIVE_ERROR);
324
325 /*
326 * DP CTS 1.2 Core Rev 1.1, 4.2.1.1 & 4.2.1.2
327 * 400us delay required for errors and timeouts
328 * Timeout errors from the HW already meet this
329 * requirement so skip to next iteration
330 */
331 if (status & (DP_AUX_CH_CTL_TIME_OUT_ERROR |
332 DP_AUX_CH_CTL_SEND_BUSY))
333 continue;
334
335 if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
336 usleep_range(400, 500);
337 continue;
338 }
339 if (status & DP_AUX_CH_CTL_DONE)
340 goto done;
341 }
342 }
343
344 if ((status & DP_AUX_CH_CTL_DONE) == 0) {
345 drm_err(&i915->drm, "%s: not done (status 0x%08x)\n",
346 intel_dp->aux.name, status);
347 ret = -EBUSY;
348 goto out;
349 }
350
351 done:
352 /*
353 * Check for timeout or receive error. Timeouts occur when the sink is
354 * not connected.
355 */
356 if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
357 drm_err(&i915->drm, "%s: receive error (status 0x%08x)\n",
358 intel_dp->aux.name, status);
359 ret = -EIO;
360 goto out;
361 }
362
363 /*
364 * Timeouts occur when the device isn't connected, so they're "normal"
365 * -- don't fill the kernel log with these
366 */
367 if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) {
368 drm_dbg_kms(&i915->drm, "%s: timeout (status 0x%08x)\n",
369 intel_dp->aux.name, status);
370 ret = -ETIMEDOUT;
371 goto out;
372 }
373
374 /* Unload any bytes sent back from the other side */
375 recv_bytes = REG_FIELD_GET(DP_AUX_CH_CTL_MESSAGE_SIZE_MASK, status);
376
377 /*
378 * By BSpec: "Message sizes of 0 or >20 are not allowed."
379 * We have no idea of what happened so we return -EBUSY so
380 * drm layer takes care for the necessary retries.
381 */
382 if (recv_bytes == 0 || recv_bytes > 20) {
383 drm_dbg_kms(&i915->drm,
384 "%s: Forbidden recv_bytes = %d on aux transaction\n",
385 intel_dp->aux.name, recv_bytes);
386 ret = -EBUSY;
387 goto out;
388 }
389
390 if (recv_bytes > recv_size)
391 recv_bytes = recv_size;
392
393 for (i = 0; i < recv_bytes; i += 4)
394 intel_dp_aux_unpack(intel_de_read(i915, ch_data[i >> 2]),
395 recv + i, recv_bytes - i);
396
397 ret = recv_bytes;
398 out:
399 cpu_latency_qos_update_request(&intel_dp->pm_qos, PM_QOS_DEFAULT_VALUE);
400
401 if (vdd)
402 intel_pps_vdd_off_unlocked(intel_dp, false);
403
404 intel_pps_unlock(intel_dp, pps_wakeref);
405 intel_display_power_put_async(i915, aux_domain, aux_wakeref);
406 out_unlock:
407 if (is_tc_port)
408 intel_tc_port_unlock(dig_port);
409
410 return ret;
411 }
412
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
More information about the Intel-gfx
mailing list