static void *psl(void *ptr) { struct cxl_afu_h *afu = (struct cxl_afu_h *)ptr; while (status.psl_state != PSL_DONE) { if (status.psl_state == PSL_INIT) { psl_signal_afu_model (status.event); status.psl_state = PSL_RUNNING; } if (status.cmd.request==AFU_REQUEST) { if (psl_job_control (status.event, status.cmd.code, status.cmd.addr) == PSL_SUCCESS) { #ifdef DEBUG printf ("Job 0x%02x\n", status.cmd.code); #endif /* #ifdef DEBUG */ if (status.cmd.code == PSL_JOB_RESET) status.cmd.request = AFU_RESET; else status.cmd.request = AFU_PENDING; continue; } } else if (status.mmio.request == AFU_REQUEST) { if (status.mmio.rnw) { if (psl_mmio_read (status.event, status.mmio.dw, status.mmio.addr, status.mmio.desc) == PSL_SUCCESS) { #ifdef DEBUG printf ("MMIO Read %d\n", status.mmio.addr); #endif /* #ifdef DEBUG */ status.mmio.request = AFU_PENDING; continue; } } else { if (psl_mmio_write (status.event, status.mmio.dw, status.mmio.addr, status.mmio.data, status.mmio.desc) == PSL_SUCCESS) { #ifdef DEBUG printf ("MMIO Write %d\n", status.mmio.addr); #endif /* #ifdef DEBUG */ status.mmio.request = AFU_PENDING; continue; } } } if (!(rand() % RESP_RANDOMIZER)) push_resp(); psl_signal_afu_model (status.event); if (psl_get_afu_events (status.event) > 0) { handle_psl_events (afu); } } pthread_exit(NULL); }
// PSL thread loop static void *_psl_loop(void *ptr) { struct psl *psl = (struct psl *)ptr; struct cmd_event *event, *temp; int events, i, stopped, reset; uint8_t ack = PSLSE_DETACH; stopped = 1; pthread_mutex_lock(psl->lock); while (psl->state != PSLSE_DONE) { // idle_cycles continues to generate clock cycles for some // time after the AFU has gone idle. Eventually clocks will // not be presented to an idle AFU to keep simulation // waveforms from getting huge with no activity cycles. if (psl->state != PSLSE_IDLE) { psl->idle_cycles = PSL_IDLE_CYCLES; if (stopped) info_msg("Clocking %s", psl->name); fflush(stdout); stopped = 0; } if (psl->idle_cycles) { // Clock AFU psl_signal_afu_model(psl->afu_event); // Check for events from AFU events = psl_get_afu_events(psl->afu_event); // Error on socket if (events < 0) { warn_msg("Lost connection with AFU"); break; } // Handle events from AFU if (events > 0) _handle_afu(psl); // Drive events to AFU send_job(psl->job); send_mmio(psl->mmio); if (psl->mmio->list == NULL) psl->idle_cycles--; } else { if (!stopped) info_msg("Stopping clocks to %s", psl->name); stopped = 1; lock_delay(psl->lock); } // Skip client section if AFU descriptor hasn't been read yet if (psl->client == NULL) { lock_delay(psl->lock); continue; } // Check for event from application reset = 0; for (i = 0; i < psl->max_clients; i++) { if (psl->client[i] == NULL) continue; if ((psl->client[i]->state == CLIENT_NONE) && (psl->client[i]->idle_cycles == 0)) { put_bytes(psl->client[i]->fd, 1, &ack, psl->dbg_fp, psl->dbg_id, psl->client[i]->context); _free(psl, psl->client[i]); psl->client[i] = NULL; reset = 1; continue; } if (psl->state == PSLSE_RESET) continue; _handle_client(psl, psl->client[i]); if (psl->client[i]->idle_cycles) { psl->client[i]->idle_cycles--; } if (client_cmd(psl->cmd, psl->client[i])) { psl->client[i]->idle_cycles = PSL_IDLE_CYCLES; } } // Send reset to AFU if (reset == 1) { psl->cmd->buffer_read = NULL; event = psl->cmd->list; while (event != NULL) { if (reset) { warn_msg ("Client dropped context before AFU completed"); reset = 0; } warn_msg("Dumping command tag=0x%02x", event->tag); if (event->data) { free(event->data); } if (event->parity) { free(event->parity); } temp = event; event = event->_next; free(temp); } psl->cmd->list = NULL; info_msg("Sending reset to AFU"); add_job(psl->job, PSL_JOB_RESET, 0L); } lock_delay(psl->lock); } // Disconnect clients for (i = 0; i < psl->max_clients; i++) { if ((psl->client != NULL) && (psl->client[i] != NULL)) { // FIXME: Send warning to clients first? info_msg("Disconnecting %s context %d", psl->name, psl->client[i]->context); close_socket(&(psl->client[i]->fd)); } } // DEBUG debug_afu_drop(psl->dbg_fp, psl->dbg_id); // Disconnect from simulator, free memory and shut down thread info_msg("Disconnecting %s @ %s:%d", psl->name, psl->host, psl->port); if (psl->client) free(psl->client); if (psl->_prev) psl->_prev->_next = psl->_next; if (psl->_next) psl->_next->_prev = psl->_prev; if (psl->cmd) { free(psl->cmd); } if (psl->job) { free(psl->job); } if (psl->mmio) { free(psl->mmio); } if (psl->host) free(psl->host); if (psl->afu_event) { psl_close_afu_event(psl->afu_event); free(psl->afu_event); } if (psl->name) free(psl->name); if (*(psl->head) == psl) *(psl->head) = psl->_next; pthread_mutex_unlock(psl->lock); free(psl); pthread_exit(NULL); }
// PSL thread loop static void *_psl_loop(void *ptr) { struct psl *psl = (struct psl *)ptr; struct cmd_event *event, *temp; int events, i, stopped, reset; uint8_t ack = PSLSE_DETACH; stopped = 1; pthread_mutex_lock(psl->lock); while (psl->state != PSLSE_DONE) { // idle_cycles continues to generate clock cycles for some // time after the AFU has gone idle. Eventually clocks will // not be presented to an idle AFU to keep simulation // waveforms from getting huge with no activity cycles. if (psl->state != PSLSE_IDLE) { // if we have clients or we are in the reset state, refresh idle_cycles // so that the afu clock will not be allowed to stop to save afu event simulator cycles if ((psl->attached_clients > 0) || (psl->state == PSLSE_RESET)) { psl->idle_cycles = PSL_IDLE_CYCLES; if (stopped) info_msg("Clocking %s", psl->name); fflush(stdout); stopped = 0; } } if (psl->idle_cycles) { // Clock AFU //printf("before psl_signal_afu_model in psl_loop \n"); psl_signal_afu_model(psl->afu_event); // Check for events from AFU events = psl_get_afu_events(psl->afu_event); //printf("after psl_get_afu_events, events is 0x%3x \n", events); // Error on socket if (events < 0) { warn_msg("Lost connection with AFU"); break; } // Handle events from AFU if (events > 0) _handle_afu(psl); // Drive events to AFU send_job(psl->job); send_pe(psl->job); send_mmio(psl->mmio); if (psl->mmio->list == NULL) psl->idle_cycles--; } else { if (!stopped) info_msg("Stopping clocks to %s", psl->name); stopped = 1; lock_delay(psl->lock); } // Skip client section if AFU descriptor hasn't been read yet if (psl->client == NULL) { lock_delay(psl->lock); continue; } // Check for event from application reset = 0; for (i = 0; i < psl->max_clients; i++) { if (psl->client[i] == NULL) continue; if ((psl->client[i]->type == 'd') && (psl->client[i]->state == CLIENT_NONE) && (psl->client[i]->idle_cycles == 0)) { // this was the old way of detaching a dedicated process app/afu pair // we get the detach message, drop the client, and wait for idle cycle to get to 0 put_bytes(psl->client[i]->fd, 1, &ack, psl->dbg_fp, psl->dbg_id, psl->client[i]->context); _free(psl, psl->client[i]); psl->client[i] = NULL; // aha - this is how we only called _free once the old way // why do we not free client[i]? // because this was a short cut pointer // the *real* client point is in client_list in pslse reset = 1; // for m/s devices we need to do this differently and not send a reset... // _handle_client - creates the llcmd's to term and remove // send_pe - sends the llcmd pe's to afu one at a time // _handle_afu calls _handle_aux2 // _handle_aux2 finishes the llcmd pe's when jcack is asserted by afu // when the remove llcmd is processed, we should put_bytes, _free and set client[i] to NULL continue; } if (psl->state == PSLSE_RESET) continue; _handle_client(psl, psl->client[i]); if (psl->client[i]->idle_cycles) { psl->client[i]->idle_cycles--; } if (client_cmd(psl->cmd, psl->client[i])) { psl->client[i]->idle_cycles = PSL_IDLE_CYCLES; } } // Send reset to AFU if (reset == 1) { psl->cmd->buffer_read = NULL; event = psl->cmd->list; while (event != NULL) { if (reset) { warn_msg ("Client dropped context before AFU completed"); reset = 0; } info_msg("Dumping command tag=0x%02x", event->tag); #ifdef PSL9 info_msg("Dumping itag=0x%02x utag=0x%02x type=0x%02x state=0x%02x", event->itag, event->utag, event->type, event->state); #endif if (event->data) { free(event->data); } if (event->parity) { free(event->parity); } temp = event; event = event->_next; free(temp); } psl->cmd->list = NULL; info_msg("Sending reset to AFU"); add_job(psl->job, PSL_JOB_RESET, 0L); } lock_delay(psl->lock); } // Disconnect clients for (i = 0; i < psl->max_clients; i++) { if ((psl->client != NULL) && (psl->client[i] != NULL)) { // FIXME: Send warning to clients first? info_msg("Disconnecting %s context %d", psl->name, psl->client[i]->context); close_socket(&(psl->client[i]->fd)); } } // DEBUG debug_afu_drop(psl->dbg_fp, psl->dbg_id); // Disconnect from simulator, free memory and shut down thread info_msg("Disconnecting %s @ %s:%d", psl->name, psl->host, psl->port); if (psl->client) free(psl->client); if (psl->_prev) psl->_prev->_next = psl->_next; if (psl->_next) psl->_next->_prev = psl->_prev; if (psl->cmd) { free(psl->cmd); } if (psl->job) { free(psl->job); } if (psl->mmio) { free(psl->mmio); } if (psl->host) free(psl->host); if (psl->afu_event) { psl_close_afu_event(psl->afu_event); free(psl->afu_event); } if (psl->name) free(psl->name); if (*(psl->head) == psl) *(psl->head) = psl->_next; pthread_mutex_unlock(psl->lock); free(psl); pthread_exit(NULL); }