/* * Check if the provided PDU size is compatible with the * channel PDU size * * Return the response to send ACK/NACK */ static int dlp_ctrl_check_pdu_size(struct dlp_channel *ch_ctx, struct dlp_command_params *params, struct dlp_command_params *tx_params) { int size, response; memcpy(tx_params, params, sizeof(struct dlp_command_params)); size = ((params->data2 << 8) | params->data1); /* OPEN_CONN => ACK by default */ response = DLP_CMD_ACK; tx_params->data3 = CMD_ID(params->data3, params->id); /* Check the requested PDU size */ if (ch_ctx->rx.pdu_size != size) { pr_err(DRVNAME ": ch%d wrong pdu size %d (expected %d)\n", ch_ctx->hsi_channel, size, ch_ctx->rx.pdu_size); /* OPEN_CONN => NACK (Unexpected PDU size) */ response = DLP_CMD_NACK; /* Set the response params */ tx_params->data1 = 0; tx_params->data2 = 0; tx_params->data3 = CMD_ID_ERR(params, EDLP_ERR_WRONG_PDU_SIZE); } return response; }
/* ARGSUSED */ static int op_sort(cmd_t *cmd, boolean_t smpl) { page_t *cur; int cmd_id; if ((cur = page_current_get()) != NULL) { cmd_id = CMD_ID(cmd); sortkey_set(cmd_id, cur); (void) op_refresh(cmd, B_FALSE); } return (0); }
/* * The common entry for processing command. */ static void cmd_received(cmd_t *cmd, boolean_t *quit, struct timespec *timeout) { boolean_t badcmd, execute; int cmd_id = CMD_ID(cmd); execute = B_TRUE; *quit = B_FALSE; switch (cmd_id) { case CMD_QUIT_ID: *quit = B_TRUE; return; case CMD_RESIZE_ID: /* * The screen resize signal would trigger this * command. Destroy existing screen and curses * resources and then re-init the curses resources. */ win_fix_fini(); page_win_destroy(); reg_curses_fini(); if (reg_curses_init(B_FALSE)) { win_fix_init(); } else { execute = B_FALSE; } timeout_set(timeout, DISP_DEFAULT_INTVAL); break; case CMD_REFRESH_ID: /* * User hit the hotkey 'R' to refresh current window. */ timeout_set(timeout, DISP_DEFAULT_INTVAL); break; } if (execute) { cmd_execute(cmd, &badcmd); } }
int os_op_callchain_count(cmd_t *cmd, boolean_t smpl) { page_t *cur; count_id_t countid; int cmd_id; if ((cur = page_current_get()) != NULL) { cmd_id = CMD_ID(cmd); if ((countid = callchain_countid_set(cmd_id, cur)) == COUNT_INVALID) { return (0); } perf_profiling_partpause(countid); op_refresh(cmd, smpl); } return (0); }
bool retrace_frame(uint64_t* num_cmds) { *num_cmds = 0; while (1) { char id = trace_read_id(); switch (id) { case TRACE_EOF: return false; case TRACE_CMD: { uint32_t cmd[CMD_MAX_INTS]; uint32_t length; trace_read_cmd(cmd, &length); rdp_cmd(cmd, length); (*num_cmds)++; if (CMD_ID(cmd) == CMD_ID_SYNC_FULL) { return true; } break; } case TRACE_RDRAM: trace_read_rdram(); break; case TRACE_VI: trace_read_vi(plugin_get_vi_registers()); vi_update(); break; } } }
/* * The common entry to process all commands. */ void cmd_execute(cmd_t *cmd, boolean_t *badcmd) { cmd_id_t cmd_id; win_type_t type; page_t *cur; switch_t *s; boolean_t b = B_TRUE, smpl = B_FALSE; if ((cmd_id = CMD_ID(cmd)) == CMD_INVALID_ID) { goto L_EXIT; } b = B_FALSE; if ((cur = page_current_get()) == NULL) { /* It's the first window. */ type = WIN_TYPE_RAW_NUM; } else { type = PAGE_WIN_TYPE(cur); } s = &s_switch[type][cmd_id]; if (s->preop != NULL) { (void) s->preop(cmd, &smpl); } if (s->op != NULL) { (void) s->op(cmd, smpl); } L_EXIT: if (badcmd != NULL) { *badcmd = b; } }
/** * Send an HSI msg AND wait for the status * * @ch_ctx: a reference to the channel context to use * @id: the DLP command id * @response_id: the expected response id * @interm_state: the intermidiate state (to be set when TX is OK) * @final_state: the final state (to be set when RX (response) is OK) * @param1: the DLP command params * @param2: the DLP command params * @param3: the DLP command params * * This function blocks the caller until a response is received * or the timeout expires */ static int dlp_ctrl_cmd_send(struct dlp_channel *ch_ctx, unsigned char id, unsigned char response_id, unsigned char interm_state, unsigned char final_state, unsigned char param1, unsigned char param2, unsigned char param3) { int ret = 0, old_state; struct dlp_ctrl_context *ctrl_ctx; struct dlp_command *dlp_cmd; struct dlp_command_params expected_resp; struct hsi_msg *tx_msg = NULL; /* Check the link readiness (TTY still opened) */ if (!dlp_tty_is_link_valid()) { if (EDLP_CTRL_TX_DATA_REPORT) pr_debug(DRVNAME ": CH%d (HSI CH%d) cmd 0x%X ignored (close:%d, Time out: %d)\n", ch_ctx->ch_id, ch_ctx->hsi_channel, id, dlp_drv.tty_closed, dlp_drv.tx_timeout); return ret; } ctrl_ctx = DLP_CTRL_CTX; mutex_lock(&ch_ctx->tx.cmd_sync); /* Save the current channel state */ old_state = dlp_ctrl_get_channel_state(ch_ctx->hsi_channel); /* Backup RX callback */ dlp_save_rx_callbacks(&ctrl_ctx->ehandler); /* Allocate the DLP command */ dlp_cmd = dlp_ctrl_cmd_alloc(ch_ctx, id, param1, param2, param3); if (!dlp_cmd) { pr_err(DRVNAME ": Out of memory (dlp_cmd: 0x%X)\n", id); ret = -ENOMEM; goto out; } /* Allocate a new TX msg */ tx_msg = dlp_pdu_alloc(DLP_CHANNEL_CTRL, HSI_MSG_WRITE, DLP_CTRL_TX_PDU_SIZE, 1, dlp_cmd, dlp_ctrl_complete_tx, dlp_ctrl_msg_destruct); if (!tx_msg) { pr_err(DRVNAME ": dlp_pdu_alloc(TX) failed\n"); ret = -ENOMEM; goto free_cmd; } /* Copy the command data */ memcpy(sg_virt(tx_msg->sgt.sgl), &dlp_cmd->params, sizeof(struct dlp_command_params)); /* Send the TX HSI msg */ ret = hsi_async(tx_msg->cl, tx_msg); if (ret) { pr_err(DRVNAME ": Unable to send 0x%X cmd (ret:%d)\n", dlp_cmd->params.id, ret); /* Free the TX msg */ dlp_pdu_free(tx_msg, tx_msg->channel); goto free_cmd; } /* Dump the TX command */ if (EDLP_CTRL_TX_DATA_REPORT) pr_debug(DRVNAME ": CTRL_TX (0x%X)\n", *((u32 *)&dlp_cmd->params)); /* Wait for TX msg to be sent */ ret = wait_for_completion_timeout(&ch_ctx->tx.cmd_xfer_done, msecs_to_jiffies(DLP_CMD_TX_TIMOUT)); if (ret == 0) { pr_err(DRVNAME ": hsi_ch:%d, cmd:0x%X => TX timeout\n", dlp_cmd->params.channel, dlp_cmd->params.id); /* No need to call the complete sending call back, * because of failure */ tx_msg->complete = NULL; tx_msg->context = NULL; ret = -EIO; /* free only the cmd, because * the message is already in the controller fifo. * It will be freed when the controller fifo will be * flushed/freed */ goto free_cmd; } /* TX msg sent, check the status */ if (dlp_cmd->status) { pr_err(DRVNAME ": Failed to send cmd:0x%X\n", dlp_cmd->params.id); ret = -EIO; /* free only the command because * the message has been already freed by the complete_tx * callback */ goto free_cmd; } /* TX OK */ /* 1. Set the intermidiate channel state */ if (interm_state != DLP_CH_STATE_NONE) dlp_ctrl_set_channel_state(ch_ctx->hsi_channel, interm_state); /* Wait for response ? */ if (response_id == DLP_CMD_NONE) { ret = 0; goto no_resp; } /* 2. Wait for the response */ ret = wait_for_completion_timeout(&ch_ctx->rx.cmd_xfer_done, msecs_to_jiffies(DLP_CMD_RX_TIMOUT)); if (ret == 0) { pr_err(DRVNAME ": hsi_ch:%d, cmd:0x%X => RX timeout\n", dlp_cmd->params.channel, dlp_cmd->params.id); ret = -EIO; goto free_cmd; } /* Set the expected response params */ expected_resp.id = response_id; expected_resp.channel = ch_ctx->hsi_channel; switch (id) { case DLP_CMD_CLOSE_CONN: expected_resp.data1 = param3; expected_resp.data2 = param2; expected_resp.data3 = CMD_ID(param1, id); break; case DLP_CMD_OPEN_CONN: default: expected_resp.data1 = param1; expected_resp.data2 = param2; expected_resp.data3 = CMD_ID(param3, id); } /* Check the received response params */ ret = 0; if (memcmp(&ctrl_ctx->response.params, &expected_resp, sizeof(expected_resp))) { pr_err(DRVNAME": cmd 0x%X unexpected response 0x%X (expected 0x%X)", id, (unsigned int)(*(u32 *)&ctrl_ctx->response.params), (unsigned int)(*(u32 *)(&expected_resp))); tx_msg->context = NULL; ret = -EIO; goto free_cmd; } no_resp: /* Response received & OK => set the new channel state */ if (final_state != DLP_CH_STATE_NONE) dlp_ctrl_set_channel_state(ch_ctx->hsi_channel, final_state); free_cmd: /* Free the DLP command */ dlp_ctrl_cmd_free(dlp_cmd); out: /* Restore RX callback */ dlp_restore_rx_callbacks(&ctrl_ctx->ehandler); /* Restore the channel state in error case */ if (ret) dlp_ctrl_set_channel_state(ch_ctx->hsi_channel, old_state); mutex_unlock(&ch_ctx->tx.cmd_sync); return ret; }
static void dlp_ctrl_complete_rx(struct hsi_msg *msg) { struct dlp_channel *ch_ctx; struct dlp_ctrl_context *ctrl_ctx; struct dlp_command *dlp_cmd = msg->context; struct dlp_command_params params, tx_params; unsigned long flags; int hsi_channel, elp_channel, ret, response, msg_complete, state; params.channel = 0; /* To please KlocWork */ /* Check the link readiness (TTY still opened) */ if (!dlp_tty_is_link_valid()) { if (EDLP_CTRL_RX_DATA_REPORT) pr_debug(DRVNAME ": CTRL: CH%d RX PDU ignored (close:%d, Time out: %d)\n", params.channel, dlp_drv.tty_closed, dlp_drv.tx_timeout); /* Delete the received msg */ dlp_pdu_free(msg, msg->channel); /* Delete the command */ dlp_ctrl_cmd_free(dlp_cmd); return; } /* Copy the reponse */ memcpy(¶ms, sg_virt(msg->sgt.sgl), sizeof(struct dlp_command_params)); ctrl_ctx = DLP_CTRL_CTX; response = -1; memcpy(&tx_params, ¶ms, sizeof(struct dlp_command_params)); msg_complete = (msg->status == HSI_STATUS_COMPLETED); /* Dump the RX command */ if (EDLP_CTRL_RX_DATA_REPORT) pr_debug(DRVNAME ": CTRL_RX (0x%X)\n", *((u32 *)¶ms)); hsi_channel = params.channel; if ((hsi_channel < 0) || (hsi_channel >= DLP_CHANNEL_COUNT)) { pr_err(DRVNAME ": Invalid HSI channel id (%d)\n", hsi_channel); goto push_rx; } elp_channel = dlp_drv.channels_hsi[hsi_channel].edlp_channel; ch_ctx = DLP_CHANNEL_CTX(elp_channel); switch (params.id) { case DLP_CMD_NOP: break; case DLP_CMD_CREDITS: if (!msg_complete) break; /* Increase the CREDITS counter */ spin_lock_irqsave(&ch_ctx->lock, flags); ch_ctx->credits += params.data3; ret = ch_ctx->credits; spin_unlock_irqrestore(&ch_ctx->lock, flags); /* Credits available ==> Notify the channel */ if (ch_ctx->credits_available_cb) ch_ctx->credits_available_cb(ch_ctx); /* CREDITS => ACK */ response = DLP_CMD_ACK; /* Set the response params */ tx_params.data1 = params.data3; tx_params.data2 = 0; tx_params.data3 = 0; break; case DLP_CMD_OPEN_CONN: if (!msg_complete) break; /* Ready ? if not, just save the OPEN_CONN request params */ spin_lock_irqsave(&ctrl_ctx->open_lock, flags); state = dlp_ctrl_get_channel_state(hsi_channel); if ((state != DLP_CH_STATE_OPENING) && (state != DLP_CH_STATE_OPENED)) { struct dlp_hsi_channel *hsi_ch; hsi_ch = &dlp_drv.channels_hsi[hsi_channel]; memcpy(&hsi_ch->open_conn, ¶ms, sizeof(params)); spin_unlock_irqrestore(&ctrl_ctx->open_lock, flags); response = -1; pr_debug(DRVNAME ": HSI CH%d OPEN_CONN received (postponed) when state is %d\n", params.channel, state); goto push_rx; } else spin_unlock_irqrestore(&ctrl_ctx->open_lock, flags); pr_debug(DRVNAME ": HSI CH%d OPEN_CONN received (size: %d)\n", params.channel, (params.data2 << 8) | params.data1); /* Check the PDU size */ response = dlp_ctrl_check_pdu_size(ch_ctx, ¶ms, &tx_params); break; case DLP_CMD_CLOSE_CONN: /* CLOSE_CONN => ACK */ response = DLP_CMD_ACK; /* Set the response params */ tx_params.data1 = params.data3; tx_params.data2 = 0; tx_params.data3 = CMD_ID(params.data3, params.id); pr_debug(DRVNAME ": ch%d close_conn received\n", params.channel); break; default: /* Save the modem response */ ctrl_ctx->response.status = (msg_complete ? 0 : -EIO); memcpy(&ctrl_ctx->response.params, ¶ms, sizeof(struct dlp_command_params)); /* Command done, notify the sender */ complete(&ch_ctx->rx.cmd_xfer_done); break; } /* Any response to send ? */ if (response == -1) goto push_rx; dlp_ctrl_send_response(ch_ctx, &tx_params, response); push_rx: /* Push the RX msg again for futur response */ ret = hsi_async(msg->cl, msg); if (ret) { pr_err(DRVNAME ": RX push failed, ret:%d\n", ret); /* We have A BIG PROBLEM if the RX msg cant be */ /* pushed again in the controller ==> */ /* No response could be received (FIFO empty) */ /* Delete the received msg */ dlp_pdu_free(msg, msg->channel); /* Delete the command */ dlp_ctrl_cmd_free(dlp_cmd); } }
void rdp_update(void) { uint32_t** dp_reg = plugin_get_dp_registers(); uint32_t dp_current_al = (*dp_reg[DP_CURRENT] & ~7) >> 2; uint32_t dp_end_al = (*dp_reg[DP_END] & ~7) >> 2; // don't do anything if the RDP has crashed or the registers are not set up correctly if (rdp_pipeline_crashed || dp_end_al <= dp_current_al) { return; } // while there's data in the command buffer... while (dp_end_al - dp_current_al > 0) { uint32_t i, toload; bool xbus_dma = (*dp_reg[DP_STATUS] & DP_STATUS_XBUS_DMA) != 0; uint32_t* dmem = (uint32_t*)plugin_get_dmem(); uint32_t* cmd_buf = rdp_cmd_buf[rdp_cmd_buf_pos]; // when reading the first int, extract the command ID and update the buffer length if (rdp_cmd_pos == 0) { if (xbus_dma) { cmd_buf[rdp_cmd_pos++] = dmem[dp_current_al++ & 0x3ff]; } else { cmd_buf[rdp_cmd_pos++] = rdram_read_idx32(dp_current_al++); } rdp_cmd_id = CMD_ID(cmd_buf); rdp_cmd_len = rdp_commands[rdp_cmd_id].length >> 2; } // copy more data from the N64 to the local command buffer toload = MIN(dp_end_al - dp_current_al, rdp_cmd_len - 1); if (xbus_dma) { for (i = 0; i < toload; i++) { cmd_buf[rdp_cmd_pos++] = dmem[dp_current_al++ & 0x3ff]; } } else { for (i = 0; i < toload; i++) { cmd_buf[rdp_cmd_pos++] = rdram_read_idx32(dp_current_al++); } } // if there's enough data for the current command... if (rdp_cmd_pos == rdp_cmd_len) { // check if parallel processing is enabled if (config.parallel) { // special case: sync_full always needs to be run in main thread if (rdp_cmd_id == CMD_ID_SYNC_FULL) { // first, run all pending commands cmd_flush(); // parameters are unused, so NULL is fine rdp_sync_full(NULL, NULL); } else { // increment buffer position rdp_cmd_buf_pos++; // flush buffer when it is full or when the current command requires a sync if (rdp_cmd_buf_pos >= CMD_BUFFER_SIZE || rdp_commands[rdp_cmd_id].sync) { cmd_flush(); } } } else { // run command directly cmd_run(&rdp_states[0], cmd_buf); } // reset current command buffer to prepare for the next one cmd_init(); } } // update DP registers to indicate that all bytes have been read *dp_reg[DP_START] = *dp_reg[DP_CURRENT] = *dp_reg[DP_END]; }
static void cmd_run(struct rdp_state* rdp, const uint32_t* arg) { uint32_t cmd_id = CMD_ID(arg); rdp_commands[cmd_id].handler(rdp, arg); }