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 #include "dc_hw_types.h" 31 #include "core_types.h" 32 33 #define CTX dc_dmub_srv->ctx 34 #define DC_LOGGER CTX->logger 35 36 static void dc_dmub_srv_construct(struct dc_dmub_srv *dc_srv, struct dc *dc, 37 struct dmub_srv *dmub) 38 { 39 dc_srv->dmub = dmub; 40 dc_srv->ctx = dc->ctx; 41 } 42 43 struct dc_dmub_srv *dc_dmub_srv_create(struct dc *dc, struct dmub_srv *dmub) 44 { 45 struct dc_dmub_srv *dc_srv = 46 kzalloc(sizeof(struct dc_dmub_srv), GFP_KERNEL); 47 48 if (dc_srv == NULL) { 49 BREAK_TO_DEBUGGER(); 50 return NULL; 51 } 52 53 dc_dmub_srv_construct(dc_srv, dc, dmub); 54 55 return dc_srv; 56 } 57 58 void dc_dmub_srv_destroy(struct dc_dmub_srv **dmub_srv) 59 { 60 if (*dmub_srv) { 61 kfree(*dmub_srv); 62 *dmub_srv = NULL; 63 } 64 } 65 66 void dc_dmub_srv_cmd_queue(struct dc_dmub_srv *dc_dmub_srv, 67 union dmub_rb_cmd *cmd) 68 { 69 struct dmub_srv *dmub = dc_dmub_srv->dmub; 70 struct dc_context *dc_ctx = dc_dmub_srv->ctx; 71 enum dmub_status status; 72 73 status = dmub_srv_cmd_queue(dmub, cmd); 74 if (status == DMUB_STATUS_OK) 75 return; 76 77 if (status != DMUB_STATUS_QUEUE_FULL) 78 goto error; 79 80 /* Execute and wait for queue to become empty again. */ 81 dc_dmub_srv_cmd_execute(dc_dmub_srv); 82 dc_dmub_srv_wait_idle(dc_dmub_srv); 83 84 /* Requeue the command. */ 85 status = dmub_srv_cmd_queue(dmub, cmd); 86 if (status == DMUB_STATUS_OK) 87 return; 88 89 error: 90 DC_ERROR("Error queuing DMUB command: status=%d\n", status); 91 dc_dmub_srv_log_diagnostic_data(dc_dmub_srv); 92 } 93 94 void dc_dmub_srv_cmd_execute(struct dc_dmub_srv *dc_dmub_srv) 95 { 96 struct dmub_srv *dmub = dc_dmub_srv->dmub; 97 struct dc_context *dc_ctx = dc_dmub_srv->ctx; 98 enum dmub_status status; 99 100 status = dmub_srv_cmd_execute(dmub); 101 if (status != DMUB_STATUS_OK) { 102 DC_ERROR("Error starting DMUB execution: status=%d\n", status); 103 dc_dmub_srv_log_diagnostic_data(dc_dmub_srv); 104 } 105 } 106 107 void dc_dmub_srv_wait_idle(struct dc_dmub_srv *dc_dmub_srv) 108 { 109 struct dmub_srv *dmub = dc_dmub_srv->dmub; 110 struct dc_context *dc_ctx = dc_dmub_srv->ctx; 111 enum dmub_status status; 112 113 status = dmub_srv_wait_for_idle(dmub, 100000); 114 if (status != DMUB_STATUS_OK) { 115 DC_ERROR("Error waiting for DMUB idle: status=%d\n", status); 116 dc_dmub_srv_log_diagnostic_data(dc_dmub_srv); 117 } 118 } 119 120 void dc_dmub_srv_clear_inbox0_ack(struct dc_dmub_srv *dmub_srv) 121 { 122 struct dmub_srv *dmub = dmub_srv->dmub; 123 struct dc_context *dc_ctx = dmub_srv->ctx; 124 enum dmub_status status = DMUB_STATUS_OK; 125 126 status = dmub_srv_clear_inbox0_ack(dmub); 127 if (status != DMUB_STATUS_OK) { 128 DC_ERROR("Error clearing INBOX0 ack: status=%d\n", status); 129 dc_dmub_srv_log_diagnostic_data(dmub_srv); 130 } 131 } 132 133 void dc_dmub_srv_wait_for_inbox0_ack(struct dc_dmub_srv *dmub_srv) 134 { 135 struct dmub_srv *dmub = dmub_srv->dmub; 136 struct dc_context *dc_ctx = dmub_srv->ctx; 137 enum dmub_status status = DMUB_STATUS_OK; 138 139 status = dmub_srv_wait_for_inbox0_ack(dmub, 100000); 140 if (status != DMUB_STATUS_OK) { 141 DC_ERROR("Error waiting for INBOX0 HW Lock Ack\n"); 142 dc_dmub_srv_log_diagnostic_data(dmub_srv); 143 } 144 } 145 146 void dc_dmub_srv_send_inbox0_cmd(struct dc_dmub_srv *dmub_srv, 147 union dmub_inbox0_data_register data) 148 { 149 struct dmub_srv *dmub = dmub_srv->dmub; 150 struct dc_context *dc_ctx = dmub_srv->ctx; 151 enum dmub_status status = DMUB_STATUS_OK; 152 153 status = dmub_srv_send_inbox0_cmd(dmub, data); 154 if (status != DMUB_STATUS_OK) { 155 DC_ERROR("Error sending INBOX0 cmd\n"); 156 dc_dmub_srv_log_diagnostic_data(dmub_srv); 157 } 158 } 159 160 bool dc_dmub_srv_cmd_with_reply_data(struct dc_dmub_srv *dc_dmub_srv, union dmub_rb_cmd *cmd) 161 { 162 struct dmub_srv *dmub; 163 enum dmub_status status; 164 165 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 166 return false; 167 168 dmub = dc_dmub_srv->dmub; 169 170 status = dmub_srv_cmd_with_reply_data(dmub, cmd); 171 if (status != DMUB_STATUS_OK) { 172 DC_LOG_DEBUG("No reply for DMUB command: status=%d\n", status); 173 return false; 174 } 175 176 return true; 177 } 178 179 void dc_dmub_srv_wait_phy_init(struct dc_dmub_srv *dc_dmub_srv) 180 { 181 struct dmub_srv *dmub = dc_dmub_srv->dmub; 182 struct dc_context *dc_ctx = dc_dmub_srv->ctx; 183 enum dmub_status status; 184 185 for (;;) { 186 /* Wait up to a second for PHY init. */ 187 status = dmub_srv_wait_for_phy_init(dmub, 1000000); 188 if (status == DMUB_STATUS_OK) 189 /* Initialization OK */ 190 break; 191 192 DC_ERROR("DMCUB PHY init failed: status=%d\n", status); 193 ASSERT(0); 194 195 if (status != DMUB_STATUS_TIMEOUT) 196 /* 197 * Server likely initialized or we don't have 198 * DMCUB HW support - this won't end. 199 */ 200 break; 201 202 /* Continue spinning so we don't hang the ASIC. */ 203 } 204 } 205 206 bool dc_dmub_srv_notify_stream_mask(struct dc_dmub_srv *dc_dmub_srv, 207 unsigned int stream_mask) 208 { 209 struct dmub_srv *dmub; 210 const uint32_t timeout = 30; 211 212 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 213 return false; 214 215 dmub = dc_dmub_srv->dmub; 216 217 return dmub_srv_send_gpint_command( 218 dmub, DMUB_GPINT__IDLE_OPT_NOTIFY_STREAM_MASK, 219 stream_mask, timeout) == DMUB_STATUS_OK; 220 } 221 222 bool dc_dmub_srv_is_restore_required(struct dc_dmub_srv *dc_dmub_srv) 223 { 224 struct dmub_srv *dmub; 225 struct dc_context *dc_ctx; 226 union dmub_fw_boot_status boot_status; 227 enum dmub_status status; 228 229 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 230 return false; 231 232 dmub = dc_dmub_srv->dmub; 233 dc_ctx = dc_dmub_srv->ctx; 234 235 status = dmub_srv_get_fw_boot_status(dmub, &boot_status); 236 if (status != DMUB_STATUS_OK) { 237 DC_ERROR("Error querying DMUB boot status: error=%d\n", status); 238 return false; 239 } 240 241 return boot_status.bits.restore_required; 242 } 243 244 bool dc_dmub_srv_get_dmub_outbox0_msg(const struct dc *dc, struct dmcub_trace_buf_entry *entry) 245 { 246 struct dmub_srv *dmub = dc->ctx->dmub_srv->dmub; 247 return dmub_srv_get_outbox0_msg(dmub, entry); 248 } 249 250 void dc_dmub_trace_event_control(struct dc *dc, bool enable) 251 { 252 dm_helpers_dmub_outbox_interrupt_control(dc->ctx, enable); 253 } 254 255 void dc_dmub_srv_query_caps_cmd(struct dmub_srv *dmub) 256 { 257 union dmub_rb_cmd cmd = { 0 }; 258 enum dmub_status status; 259 260 if (!dmub) { 261 return; 262 } 263 264 memset(&cmd, 0, sizeof(cmd)); 265 266 /* Prepare fw command */ 267 cmd.query_feature_caps.header.type = DMUB_CMD__QUERY_FEATURE_CAPS; 268 cmd.query_feature_caps.header.sub_type = 0; 269 cmd.query_feature_caps.header.ret_status = 1; 270 cmd.query_feature_caps.header.payload_bytes = sizeof(struct dmub_cmd_query_feature_caps_data); 271 272 /* Send command to fw */ 273 status = dmub_srv_cmd_with_reply_data(dmub, &cmd); 274 275 ASSERT(status == DMUB_STATUS_OK); 276 277 /* If command was processed, copy feature caps to dmub srv */ 278 if (status == DMUB_STATUS_OK && 279 cmd.query_feature_caps.header.ret_status == 0) { 280 memcpy(&dmub->feature_caps, 281 &cmd.query_feature_caps.query_feature_caps_data, 282 sizeof(struct dmub_feature_caps)); 283 } 284 } 285 286 bool dc_dmub_srv_get_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv, struct dmub_diagnostic_data *diag_data) 287 { 288 if (!dc_dmub_srv || !dc_dmub_srv->dmub || !diag_data) 289 return false; 290 return dmub_srv_get_diagnostic_data(dc_dmub_srv->dmub, diag_data); 291 } 292 293 void dc_dmub_srv_log_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv) 294 { 295 struct dmub_diagnostic_data diag_data = {0}; 296 297 if (!dc_dmub_srv || !dc_dmub_srv->dmub) { 298 DC_LOG_ERROR("%s: invalid parameters.", __func__); 299 return; 300 } 301 302 if (!dc_dmub_srv_get_diagnostic_data(dc_dmub_srv, &diag_data)) { 303 DC_LOG_ERROR("%s: dc_dmub_srv_get_diagnostic_data failed.", __func__); 304 return; 305 } 306 307 DC_LOG_DEBUG( 308 "DMCUB STATE\n" 309 " dmcub_version : %08x\n" 310 " scratch [0] : %08x\n" 311 " scratch [1] : %08x\n" 312 " scratch [2] : %08x\n" 313 " scratch [3] : %08x\n" 314 " scratch [4] : %08x\n" 315 " scratch [5] : %08x\n" 316 " scratch [6] : %08x\n" 317 " scratch [7] : %08x\n" 318 " scratch [8] : %08x\n" 319 " scratch [9] : %08x\n" 320 " scratch [10] : %08x\n" 321 " scratch [11] : %08x\n" 322 " scratch [12] : %08x\n" 323 " scratch [13] : %08x\n" 324 " scratch [14] : %08x\n" 325 " scratch [15] : %08x\n" 326 " pc : %08x\n" 327 " unk_fault_addr : %08x\n" 328 " inst_fault_addr : %08x\n" 329 " data_fault_addr : %08x\n" 330 " inbox1_rptr : %08x\n" 331 " inbox1_wptr : %08x\n" 332 " inbox1_size : %08x\n" 333 " inbox0_rptr : %08x\n" 334 " inbox0_wptr : %08x\n" 335 " inbox0_size : %08x\n" 336 " is_enabled : %d\n" 337 " is_soft_reset : %d\n" 338 " is_secure_reset : %d\n" 339 " is_traceport_en : %d\n" 340 " is_cw0_en : %d\n" 341 " is_cw6_en : %d\n", 342 diag_data.dmcub_version, 343 diag_data.scratch[0], 344 diag_data.scratch[1], 345 diag_data.scratch[2], 346 diag_data.scratch[3], 347 diag_data.scratch[4], 348 diag_data.scratch[5], 349 diag_data.scratch[6], 350 diag_data.scratch[7], 351 diag_data.scratch[8], 352 diag_data.scratch[9], 353 diag_data.scratch[10], 354 diag_data.scratch[11], 355 diag_data.scratch[12], 356 diag_data.scratch[13], 357 diag_data.scratch[14], 358 diag_data.scratch[15], 359 diag_data.pc, 360 diag_data.undefined_address_fault_addr, 361 diag_data.inst_fetch_fault_addr, 362 diag_data.data_write_fault_addr, 363 diag_data.inbox1_rptr, 364 diag_data.inbox1_wptr, 365 diag_data.inbox1_size, 366 diag_data.inbox0_rptr, 367 diag_data.inbox0_wptr, 368 diag_data.inbox0_size, 369 diag_data.is_dmcub_enabled, 370 diag_data.is_dmcub_soft_reset, 371 diag_data.is_dmcub_secure_reset, 372 diag_data.is_traceport_en, 373 diag_data.is_cw0_enabled, 374 diag_data.is_cw6_enabled); 375 } 376