1 /* 2 * Copyright 2019 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: AMD 23 * 24 */ 25 26 #include "dc.h" 27 #include "dc_dmub_srv.h" 28 #include "../dmub/dmub_srv.h" 29 #include "dm_helpers.h" 30 31 #define CTX dc_dmub_srv->ctx 32 #define DC_LOGGER CTX->logger 33 34 static void dc_dmub_srv_construct(struct dc_dmub_srv *dc_srv, struct dc *dc, 35 struct dmub_srv *dmub) 36 { 37 dc_srv->dmub = dmub; 38 dc_srv->ctx = dc->ctx; 39 } 40 41 struct dc_dmub_srv *dc_dmub_srv_create(struct dc *dc, struct dmub_srv *dmub) 42 { 43 struct dc_dmub_srv *dc_srv = 44 kzalloc(sizeof(struct dc_dmub_srv), GFP_KERNEL); 45 46 if (dc_srv == NULL) { 47 BREAK_TO_DEBUGGER(); 48 return NULL; 49 } 50 51 dc_dmub_srv_construct(dc_srv, dc, dmub); 52 53 return dc_srv; 54 } 55 56 void dc_dmub_srv_destroy(struct dc_dmub_srv **dmub_srv) 57 { 58 if (*dmub_srv) { 59 kfree(*dmub_srv); 60 *dmub_srv = NULL; 61 } 62 } 63 64 void dc_dmub_srv_cmd_queue(struct dc_dmub_srv *dc_dmub_srv, 65 union dmub_rb_cmd *cmd) 66 { 67 struct dmub_srv *dmub = dc_dmub_srv->dmub; 68 struct dc_context *dc_ctx = dc_dmub_srv->ctx; 69 enum dmub_status status; 70 71 status = dmub_srv_cmd_queue(dmub, cmd); 72 if (status == DMUB_STATUS_OK) 73 return; 74 75 if (status != DMUB_STATUS_QUEUE_FULL) 76 goto error; 77 78 /* Execute and wait for queue to become empty again. */ 79 dc_dmub_srv_cmd_execute(dc_dmub_srv); 80 dc_dmub_srv_wait_idle(dc_dmub_srv); 81 82 /* Requeue the command. */ 83 status = dmub_srv_cmd_queue(dmub, cmd); 84 if (status == DMUB_STATUS_OK) 85 return; 86 87 error: 88 DC_ERROR("Error queuing DMUB command: status=%d\n", status); 89 dc_dmub_srv_log_diagnostic_data(dc_dmub_srv); 90 } 91 92 void dc_dmub_srv_cmd_execute(struct dc_dmub_srv *dc_dmub_srv) 93 { 94 struct dmub_srv *dmub = dc_dmub_srv->dmub; 95 struct dc_context *dc_ctx = dc_dmub_srv->ctx; 96 enum dmub_status status; 97 98 status = dmub_srv_cmd_execute(dmub); 99 if (status != DMUB_STATUS_OK) { 100 DC_ERROR("Error starting DMUB execution: status=%d\n", status); 101 dc_dmub_srv_log_diagnostic_data(dc_dmub_srv); 102 } 103 } 104 105 void dc_dmub_srv_wait_idle(struct dc_dmub_srv *dc_dmub_srv) 106 { 107 struct dmub_srv *dmub = dc_dmub_srv->dmub; 108 struct dc_context *dc_ctx = dc_dmub_srv->ctx; 109 enum dmub_status status; 110 111 status = dmub_srv_wait_for_idle(dmub, 100000); 112 if (status != DMUB_STATUS_OK) { 113 DC_ERROR("Error waiting for DMUB idle: status=%d\n", status); 114 dc_dmub_srv_log_diagnostic_data(dc_dmub_srv); 115 } 116 } 117 118 void dc_dmub_srv_clear_inbox0_ack(struct dc_dmub_srv *dmub_srv) 119 { 120 struct dmub_srv *dmub = dmub_srv->dmub; 121 struct dc_context *dc_ctx = dmub_srv->ctx; 122 enum dmub_status status = DMUB_STATUS_OK; 123 124 status = dmub_srv_clear_inbox0_ack(dmub); 125 if (status != DMUB_STATUS_OK) { 126 DC_ERROR("Error clearing INBOX0 ack: status=%d\n", status); 127 dc_dmub_srv_log_diagnostic_data(dmub_srv); 128 } 129 } 130 131 void dc_dmub_srv_wait_for_inbox0_ack(struct dc_dmub_srv *dmub_srv) 132 { 133 struct dmub_srv *dmub = dmub_srv->dmub; 134 struct dc_context *dc_ctx = dmub_srv->ctx; 135 enum dmub_status status = DMUB_STATUS_OK; 136 137 status = dmub_srv_wait_for_inbox0_ack(dmub, 100000); 138 if (status != DMUB_STATUS_OK) { 139 DC_ERROR("Error waiting for INBOX0 HW Lock Ack\n"); 140 dc_dmub_srv_log_diagnostic_data(dmub_srv); 141 } 142 } 143 144 void dc_dmub_srv_send_inbox0_cmd(struct dc_dmub_srv *dmub_srv, 145 union dmub_inbox0_data_register data) 146 { 147 struct dmub_srv *dmub = dmub_srv->dmub; 148 struct dc_context *dc_ctx = dmub_srv->ctx; 149 enum dmub_status status = DMUB_STATUS_OK; 150 151 status = dmub_srv_send_inbox0_cmd(dmub, data); 152 if (status != DMUB_STATUS_OK) { 153 DC_ERROR("Error sending INBOX0 cmd\n"); 154 dc_dmub_srv_log_diagnostic_data(dmub_srv); 155 } 156 } 157 158 bool dc_dmub_srv_cmd_with_reply_data(struct dc_dmub_srv *dc_dmub_srv, union dmub_rb_cmd *cmd) 159 { 160 struct dmub_srv *dmub; 161 enum dmub_status status; 162 163 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 164 return false; 165 166 dmub = dc_dmub_srv->dmub; 167 168 status = dmub_srv_cmd_with_reply_data(dmub, cmd); 169 if (status != DMUB_STATUS_OK) { 170 DC_LOG_DEBUG("No reply for DMUB command: status=%d\n", status); 171 return false; 172 } 173 174 return true; 175 } 176 177 void dc_dmub_srv_wait_phy_init(struct dc_dmub_srv *dc_dmub_srv) 178 { 179 struct dmub_srv *dmub = dc_dmub_srv->dmub; 180 struct dc_context *dc_ctx = dc_dmub_srv->ctx; 181 enum dmub_status status; 182 183 for (;;) { 184 /* Wait up to a second for PHY init. */ 185 status = dmub_srv_wait_for_phy_init(dmub, 1000000); 186 if (status == DMUB_STATUS_OK) 187 /* Initialization OK */ 188 break; 189 190 DC_ERROR("DMCUB PHY init failed: status=%d\n", status); 191 ASSERT(0); 192 193 if (status != DMUB_STATUS_TIMEOUT) 194 /* 195 * Server likely initialized or we don't have 196 * DMCUB HW support - this won't end. 197 */ 198 break; 199 200 /* Continue spinning so we don't hang the ASIC. */ 201 } 202 } 203 204 bool dc_dmub_srv_notify_stream_mask(struct dc_dmub_srv *dc_dmub_srv, 205 unsigned int stream_mask) 206 { 207 struct dmub_srv *dmub; 208 const uint32_t timeout = 30; 209 210 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 211 return false; 212 213 dmub = dc_dmub_srv->dmub; 214 215 return dmub_srv_send_gpint_command( 216 dmub, DMUB_GPINT__IDLE_OPT_NOTIFY_STREAM_MASK, 217 stream_mask, timeout) == DMUB_STATUS_OK; 218 } 219 220 bool dc_dmub_srv_is_restore_required(struct dc_dmub_srv *dc_dmub_srv) 221 { 222 struct dmub_srv *dmub; 223 struct dc_context *dc_ctx; 224 union dmub_fw_boot_status boot_status; 225 enum dmub_status status; 226 227 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 228 return false; 229 230 dmub = dc_dmub_srv->dmub; 231 dc_ctx = dc_dmub_srv->ctx; 232 233 status = dmub_srv_get_fw_boot_status(dmub, &boot_status); 234 if (status != DMUB_STATUS_OK) { 235 DC_ERROR("Error querying DMUB boot status: error=%d\n", status); 236 return false; 237 } 238 239 return boot_status.bits.restore_required; 240 } 241 242 bool dc_dmub_srv_get_dmub_outbox0_msg(const struct dc *dc, struct dmcub_trace_buf_entry *entry) 243 { 244 struct dmub_srv *dmub = dc->ctx->dmub_srv->dmub; 245 return dmub_srv_get_outbox0_msg(dmub, entry); 246 } 247 248 void dc_dmub_trace_event_control(struct dc *dc, bool enable) 249 { 250 dm_helpers_dmub_outbox_interrupt_control(dc->ctx, enable); 251 } 252 253 bool dc_dmub_srv_get_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv, struct dmub_diagnostic_data *diag_data) 254 { 255 if (!dc_dmub_srv || !dc_dmub_srv->dmub || !diag_data) 256 return false; 257 return dmub_srv_get_diagnostic_data(dc_dmub_srv->dmub, diag_data); 258 } 259 260 void dc_dmub_srv_log_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv) 261 { 262 struct dmub_diagnostic_data diag_data = {0}; 263 264 if (!dc_dmub_srv || !dc_dmub_srv->dmub) { 265 DC_LOG_ERROR("%s: invalid parameters.", __func__); 266 return; 267 } 268 269 if (!dc_dmub_srv_get_diagnostic_data(dc_dmub_srv, &diag_data)) { 270 DC_LOG_ERROR("%s: dc_dmub_srv_get_diagnostic_data failed.", __func__); 271 return; 272 } 273 274 DC_LOG_DEBUG( 275 "DMCUB STATE\n" 276 " dmcub_version : %08x\n" 277 " scratch [0] : %08x\n" 278 " scratch [1] : %08x\n" 279 " scratch [2] : %08x\n" 280 " scratch [3] : %08x\n" 281 " scratch [4] : %08x\n" 282 " scratch [5] : %08x\n" 283 " scratch [6] : %08x\n" 284 " scratch [7] : %08x\n" 285 " scratch [8] : %08x\n" 286 " scratch [9] : %08x\n" 287 " scratch [10] : %08x\n" 288 " scratch [11] : %08x\n" 289 " scratch [12] : %08x\n" 290 " scratch [13] : %08x\n" 291 " scratch [14] : %08x\n" 292 " scratch [15] : %08x\n" 293 " pc : %08x\n" 294 " unk_fault_addr : %08x\n" 295 " inst_fault_addr : %08x\n" 296 " data_fault_addr : %08x\n" 297 " inbox1_rptr : %08x\n" 298 " inbox1_wptr : %08x\n" 299 " inbox1_size : %08x\n" 300 " inbox0_rptr : %08x\n" 301 " inbox0_wptr : %08x\n" 302 " inbox0_size : %08x\n" 303 " is_enabled : %d\n" 304 " is_soft_reset : %d\n" 305 " is_secure_reset : %d\n" 306 " is_traceport_en : %d\n" 307 " is_cw0_en : %d\n" 308 " is_cw6_en : %d\n", 309 diag_data.dmcub_version, 310 diag_data.scratch[0], 311 diag_data.scratch[1], 312 diag_data.scratch[2], 313 diag_data.scratch[3], 314 diag_data.scratch[4], 315 diag_data.scratch[5], 316 diag_data.scratch[6], 317 diag_data.scratch[7], 318 diag_data.scratch[8], 319 diag_data.scratch[9], 320 diag_data.scratch[10], 321 diag_data.scratch[11], 322 diag_data.scratch[12], 323 diag_data.scratch[13], 324 diag_data.scratch[14], 325 diag_data.scratch[15], 326 diag_data.pc, 327 diag_data.undefined_address_fault_addr, 328 diag_data.inst_fetch_fault_addr, 329 diag_data.data_write_fault_addr, 330 diag_data.inbox1_rptr, 331 diag_data.inbox1_wptr, 332 diag_data.inbox1_size, 333 diag_data.inbox0_rptr, 334 diag_data.inbox0_wptr, 335 diag_data.inbox0_size, 336 diag_data.is_dmcub_enabled, 337 diag_data.is_dmcub_soft_reset, 338 diag_data.is_dmcub_secure_reset, 339 diag_data.is_traceport_en, 340 diag_data.is_cw0_enabled, 341 diag_data.is_cw6_enabled); 342 } 343