cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dc_dmub_srv.c (9562B)


      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
     34static 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
     41struct 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
     56void 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
     64void 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
     87error:
     88	DC_ERROR("Error queuing DMUB command: status=%d\n", status);
     89	dc_dmub_srv_log_diagnostic_data(dc_dmub_srv);
     90}
     91
     92void 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
    105void 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
    118void 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
    131void 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
    144void 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
    158bool 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
    177void 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
    204bool 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
    220bool 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
    242bool 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
    248void dc_dmub_trace_event_control(struct dc *dc, bool enable)
    249{
    250	dm_helpers_dmub_outbox_interrupt_control(dc->ctx, enable);
    251}
    252
    253bool 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
    260void 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}