| 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | /* |
| 3 | * (C) COPYRIGHT 2019 ARM Limited. All rights reserved. |
| 4 | * Author: James.Qian.Wang <james.qian.wang@arm.com> |
| 5 | * |
| 6 | */ |
| 7 | #include <drm/drm_atomic.h> |
| 8 | #include <drm/drm_print.h> |
| 9 | |
| 10 | #include "komeda_dev.h" |
| 11 | |
| 12 | struct komeda_str { |
| 13 | char *str; |
| 14 | u32 sz; |
| 15 | u32 len; |
| 16 | }; |
| 17 | |
| 18 | /* return 0 on success, < 0 on no space. |
| 19 | */ |
| 20 | __printf(2, 3) |
| 21 | static int komeda_sprintf(struct komeda_str *str, const char *fmt, ...) |
| 22 | { |
| 23 | va_list args; |
| 24 | int num, free_sz; |
| 25 | int err; |
| 26 | |
| 27 | free_sz = str->sz - str->len - 1; |
| 28 | if (free_sz <= 0) |
| 29 | return -ENOSPC; |
| 30 | |
| 31 | va_start(args, fmt); |
| 32 | |
| 33 | num = vsnprintf(buf: str->str + str->len, size: free_sz, fmt, args); |
| 34 | |
| 35 | va_end(args); |
| 36 | |
| 37 | if (num < free_sz) { |
| 38 | str->len += num; |
| 39 | err = 0; |
| 40 | } else { |
| 41 | str->len = str->sz - 1; |
| 42 | err = -ENOSPC; |
| 43 | } |
| 44 | |
| 45 | return err; |
| 46 | } |
| 47 | |
| 48 | static void evt_sprintf(struct komeda_str *str, u64 evt, const char *msg) |
| 49 | { |
| 50 | if (evt) |
| 51 | komeda_sprintf(str, fmt: msg); |
| 52 | } |
| 53 | |
| 54 | static void evt_str(struct komeda_str *str, u64 events) |
| 55 | { |
| 56 | if (events == 0ULL) { |
| 57 | komeda_sprintf(str, fmt: "None" ); |
| 58 | return; |
| 59 | } |
| 60 | |
| 61 | evt_sprintf(str, evt: events & KOMEDA_EVENT_VSYNC, msg: "VSYNC|" ); |
| 62 | evt_sprintf(str, evt: events & KOMEDA_EVENT_FLIP, msg: "FLIP|" ); |
| 63 | evt_sprintf(str, evt: events & KOMEDA_EVENT_EOW, msg: "EOW|" ); |
| 64 | evt_sprintf(str, evt: events & KOMEDA_EVENT_MODE, msg: "OP-MODE|" ); |
| 65 | |
| 66 | evt_sprintf(str, evt: events & KOMEDA_EVENT_URUN, msg: "UNDERRUN|" ); |
| 67 | evt_sprintf(str, evt: events & KOMEDA_EVENT_OVR, msg: "OVERRUN|" ); |
| 68 | |
| 69 | /* GLB error */ |
| 70 | evt_sprintf(str, evt: events & KOMEDA_ERR_MERR, msg: "MERR|" ); |
| 71 | evt_sprintf(str, evt: events & KOMEDA_ERR_FRAMETO, msg: "FRAMETO|" ); |
| 72 | |
| 73 | /* DOU error */ |
| 74 | evt_sprintf(str, evt: events & KOMEDA_ERR_DRIFTTO, msg: "DRIFTTO|" ); |
| 75 | evt_sprintf(str, evt: events & KOMEDA_ERR_FRAMETO, msg: "FRAMETO|" ); |
| 76 | evt_sprintf(str, evt: events & KOMEDA_ERR_TETO, msg: "TETO|" ); |
| 77 | evt_sprintf(str, evt: events & KOMEDA_ERR_CSCE, msg: "CSCE|" ); |
| 78 | |
| 79 | /* LPU errors or events */ |
| 80 | evt_sprintf(str, evt: events & KOMEDA_EVENT_IBSY, msg: "IBSY|" ); |
| 81 | evt_sprintf(str, evt: events & KOMEDA_EVENT_EMPTY, msg: "EMPTY|" ); |
| 82 | evt_sprintf(str, evt: events & KOMEDA_EVENT_FULL, msg: "FULL|" ); |
| 83 | evt_sprintf(str, evt: events & KOMEDA_ERR_AXIE, msg: "AXIE|" ); |
| 84 | evt_sprintf(str, evt: events & KOMEDA_ERR_ACE0, msg: "ACE0|" ); |
| 85 | evt_sprintf(str, evt: events & KOMEDA_ERR_ACE1, msg: "ACE1|" ); |
| 86 | evt_sprintf(str, evt: events & KOMEDA_ERR_ACE2, msg: "ACE2|" ); |
| 87 | evt_sprintf(str, evt: events & KOMEDA_ERR_ACE3, msg: "ACE3|" ); |
| 88 | |
| 89 | /* LPU TBU errors*/ |
| 90 | evt_sprintf(str, evt: events & KOMEDA_ERR_TCF, msg: "TCF|" ); |
| 91 | evt_sprintf(str, evt: events & KOMEDA_ERR_TTNG, msg: "TTNG|" ); |
| 92 | evt_sprintf(str, evt: events & KOMEDA_ERR_TITR, msg: "TITR|" ); |
| 93 | evt_sprintf(str, evt: events & KOMEDA_ERR_TEMR, msg: "TEMR|" ); |
| 94 | evt_sprintf(str, evt: events & KOMEDA_ERR_TTF, msg: "TTF|" ); |
| 95 | |
| 96 | /* CU errors*/ |
| 97 | evt_sprintf(str, evt: events & KOMEDA_ERR_CPE, msg: "COPROC|" ); |
| 98 | evt_sprintf(str, evt: events & KOMEDA_ERR_ZME, msg: "ZME|" ); |
| 99 | evt_sprintf(str, evt: events & KOMEDA_ERR_CFGE, msg: "CFGE|" ); |
| 100 | evt_sprintf(str, evt: events & KOMEDA_ERR_TEMR, msg: "TEMR|" ); |
| 101 | |
| 102 | if (str->len > 0 && (str->str[str->len - 1] == '|')) { |
| 103 | str->str[str->len - 1] = 0; |
| 104 | str->len--; |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | static bool is_new_frame(struct komeda_events *a) |
| 109 | { |
| 110 | return (a->pipes[0] | a->pipes[1]) & |
| 111 | (KOMEDA_EVENT_FLIP | KOMEDA_EVENT_EOW); |
| 112 | } |
| 113 | |
| 114 | void komeda_print_events(struct komeda_events *evts, struct drm_device *dev) |
| 115 | { |
| 116 | u64 print_evts = 0; |
| 117 | static bool en_print = true; |
| 118 | struct komeda_dev *mdev = dev->dev_private; |
| 119 | u16 const err_verbosity = mdev->err_verbosity; |
| 120 | u64 evts_mask = evts->global | evts->pipes[0] | evts->pipes[1]; |
| 121 | |
| 122 | /* reduce the same msg print, only print the first evt for one frame */ |
| 123 | if (evts->global || is_new_frame(a: evts)) |
| 124 | en_print = true; |
| 125 | if (!(err_verbosity & KOMEDA_DEV_PRINT_DISABLE_RATELIMIT) && !en_print) |
| 126 | return; |
| 127 | |
| 128 | if (err_verbosity & KOMEDA_DEV_PRINT_ERR_EVENTS) |
| 129 | print_evts |= KOMEDA_ERR_EVENTS; |
| 130 | if (err_verbosity & KOMEDA_DEV_PRINT_WARN_EVENTS) |
| 131 | print_evts |= KOMEDA_WARN_EVENTS; |
| 132 | if (err_verbosity & KOMEDA_DEV_PRINT_INFO_EVENTS) |
| 133 | print_evts |= KOMEDA_INFO_EVENTS; |
| 134 | |
| 135 | if (evts_mask & print_evts) { |
| 136 | char msg[256]; |
| 137 | struct komeda_str str; |
| 138 | struct drm_printer p = drm_info_printer(dev: dev->dev); |
| 139 | |
| 140 | str.str = msg; |
| 141 | str.sz = sizeof(msg); |
| 142 | str.len = 0; |
| 143 | |
| 144 | komeda_sprintf(str: &str, fmt: "gcu: " ); |
| 145 | evt_str(str: &str, events: evts->global); |
| 146 | komeda_sprintf(str: &str, fmt: ", pipes[0]: " ); |
| 147 | evt_str(str: &str, events: evts->pipes[0]); |
| 148 | komeda_sprintf(str: &str, fmt: ", pipes[1]: " ); |
| 149 | evt_str(str: &str, events: evts->pipes[1]); |
| 150 | |
| 151 | DRM_ERROR("err detect: %s\n" , msg); |
| 152 | if ((err_verbosity & KOMEDA_DEV_PRINT_DUMP_STATE_ON_EVENT) && |
| 153 | (evts_mask & (KOMEDA_ERR_EVENTS | KOMEDA_WARN_EVENTS))) |
| 154 | drm_state_dump(dev, p: &p); |
| 155 | |
| 156 | en_print = false; |
| 157 | } |
| 158 | } |
| 159 | |