// Handle events from AFU static void _handle_afu(struct psl *psl) { struct client *client; uint64_t error; uint8_t *buffer; int reset_done; size_t size; reset_done = handle_aux2(psl->job, &(psl->parity_enabled), &(psl->latency), &error); if (error && !directed_mode_support(psl->mmio)) { client = psl->client[0]; size = 1 + sizeof(uint64_t); buffer = (uint8_t *) malloc(size); buffer[0] = PSLSE_AFU_ERROR; error = htonll(error); memcpy((char *)&(buffer[1]), (char *)&error, sizeof(error)); if (put_bytes (client->fd, size, buffer, psl->dbg_fp, psl->dbg_id, 0) < 0) { client_drop(client, PSL_IDLE_CYCLES, CLIENT_NONE); } } handle_mmio_ack(psl->mmio, psl->parity_enabled); if (psl->cmd != NULL) { if (reset_done) psl->cmd->credits = psl->cmd->parms->credits; handle_response(psl->cmd); handle_buffer_write(psl->cmd); handle_buffer_read(psl->cmd); handle_buffer_data(psl->cmd, psl->parity_enabled); handle_mem_write(psl->cmd); handle_touch(psl->cmd); handle_cmd(psl->cmd, psl->parity_enabled, psl->latency); handle_interrupt(psl->cmd); } }
// Client is detaching from the AFU static void _detach(struct psl *psl, struct client *client) { uint64_t wed; debug_msg("DETACH from client context 0x%02x", client->context); // if dedicated mode just drop the client // if afu-directed mode // add llcmd terminate to psl->job->pe // add llcmd remove to psl->job->pe // comment - check to see if send pe is called if the client state is CLIENT_NONE // allow the socket to close and the client struct to be freed. if (client->type == 'm' || client->type == 's') { wed = PSL_LLCMD_TERMINATE; wed = wed | (uint64_t)client->context; if (add_pe(psl->job, PSL_JOB_LLCMD, wed) == NULL) { // error error_msg( "%s:_detach failed to add llcmd terminate for context=%d"PRIx64, psl->name, client->context ); } wed = PSL_LLCMD_REMOVE; wed = wed | (uint64_t)client->context; if (add_pe(psl->job, PSL_JOB_LLCMD, wed) == NULL) { // error error_msg( "%s:_detach failed to add llcmd remove for context=%d"PRIx64, psl->name, client->context ); } } else { if (client->type == 'd' ) { client_drop(client, PSL_IDLE_CYCLES, CLIENT_NONE); } } // we will let _psl_loop call send_pe to issue the llcmds // when the jcack's come back, we will // send the detach response to the client and // free the client structure }
static void _handle_client(struct psl *psl, struct client *client) { struct mmio_event *mmio; struct cmd_event *cmd; uint8_t buffer[MAX_LINE_CHARS]; int dw = 0; // Handle MMIO done if (client->mmio_access != NULL) { client->idle_cycles = PSL_IDLE_CYCLES; client->mmio_access = handle_mmio_done(psl->mmio, client); } // Client disconnected if (client->state == CLIENT_NONE) return; // Check for event from application cmd = (struct cmd_event *)client->mem_access; mmio = NULL; if (bytes_ready(client->fd, 1, &(client->abort))) { if (get_bytes(client->fd, 1, buffer, psl->timeout, &(client->abort), psl->dbg_fp, psl->dbg_id, client->context) < 0) { client_drop(client, PSL_IDLE_CYCLES, CLIENT_NONE); return; } switch (buffer[0]) { case PSLSE_DETACH: client_drop(client, PSL_IDLE_CYCLES, CLIENT_NONE); break; case PSLSE_ATTACH: _attach(psl, client); break; case PSLSE_MEM_FAILURE: if (client->mem_access != NULL) handle_aerror(psl->cmd, cmd); client->mem_access = NULL; break; case PSLSE_MEM_SUCCESS: if (client->mem_access != NULL) handle_mem_return(psl->cmd, cmd, client->fd); client->mem_access = NULL; break; case PSLSE_MMIO_MAP: handle_mmio_map(psl->mmio, client); break; case PSLSE_MMIO_WRITE64: dw = 1; case PSLSE_MMIO_WRITE32: /*fall through */ mmio = handle_mmio(psl->mmio, client, 0, dw); break; case PSLSE_MMIO_READ64: dw = 1; case PSLSE_MMIO_READ32: /*fall through */ mmio = handle_mmio(psl->mmio, client, 1, dw); break; default: error_msg("Unexpected 0x%02x from client", buffer[0]); } if (mmio) client->mmio_access = (void *)mmio; if (client->state == CLIENT_VALID) client->idle_cycles = PSL_IDLE_CYCLES; } }
static void *_client_loop(void *ptr) { struct client *client = (struct client *)ptr; uint8_t data[2]; int rc; pthread_mutex_lock(&lock); while (client->pending) { rc = bytes_ready(client->fd, client->timeout, &(client->abort)); if (rc == 0) { lock_delay(&lock); continue; } if ((rc < 0) || get_bytes(client->fd, 1, data, 10, &(client->abort), fp, -1, -1) < 0) { client_drop(client, PSL_IDLE_CYCLES, CLIENT_NONE); break; } if (data[0] == PSLSE_QUERY) { if (get_bytes_silent(client->fd, 1, data, timeout, &(client->abort)) < 0) { debug_msg("_client_loop failed PSLSE_QUERY"); client_drop(client, PSL_IDLE_CYCLES, CLIENT_NONE); break; } _query(client, data[0]); lock_delay(&lock); continue; } if (data[0] == PSLSE_MAX_INT) { if (get_bytes(client->fd, 2, data, timeout, &(client->abort), fp, -1, -1) < 0) { client_drop(client, PSL_IDLE_CYCLES, CLIENT_NONE); break; } _max_irqs(client, data[0]); lock_delay(&lock); continue; } if (data[0] == PSLSE_OPEN) { if (get_bytes_silent(client->fd, 2, data, timeout, &(client->abort)) < 0) { client_drop(client, PSL_IDLE_CYCLES, CLIENT_NONE); debug_msg("_client_loop: client associate failed; could not communicate with socket"); break; } _client_associate(client, data[0], (char)data[1]); debug_msg("_client_loop: client associated"); break; } client->pending = 0; break; lock_delay(&lock); } pthread_mutex_unlock(&lock); // Terminate thread pthread_exit(NULL); }
// Handle randomly selected pending read by either generating early buffer // write with bogus data, send request to client for real data or do final // buffer write with valid data after it has been received from client. void handle_buffer_write(struct cmd *cmd) { struct cmd_event *event; struct client *client; uint8_t buffer[10]; uint64_t *addr; int quadrant, byte; // Make sure cmd structure is valid if (cmd == NULL) return; // Randomly select a pending read (or none) event = cmd->list; while (event != NULL) { if ((event->type == CMD_READ) && (event->state != MEM_DONE) && ((event->client_state != CLIENT_VALID) || !allow_reorder(cmd->parms))) { break; } event = event->_next; } // Test for client disconnect if ((event == NULL) || ((client = _get_client(cmd, event)) == NULL)) return; // After the client returns data with a call to the function // _handle_mem_read() issue buffer write with valid data and // prepare for response. if (event->state == MEM_RECEIVED) { if (psl_buffer_write(cmd->afu_event, event->tag, event->addr, CACHELINE_BYTES, event->data, event->parity) == PSL_SUCCESS) { debug_msg("%s:BUFFER WRITE tag=0x%02x", cmd->afu_name, event->tag); for (quadrant = 0; quadrant < 4; quadrant++) { DPRINTF("DEBUG: Q%d 0x", quadrant); for (byte = 0; byte < CACHELINE_BYTES / 4; byte++) { DPRINTF("%02x", event->data[byte]); } DPRINTF("\n"); } event->resp = PSL_RESPONSE_DONE; event->state = MEM_DONE; debug_cmd_buffer_write(cmd->dbg_fp, cmd->dbg_id, event->tag); debug_cmd_update(cmd->dbg_fp, cmd->dbg_id, event->tag, event->context, event->resp); } } if (event->state != MEM_IDLE) return; if (!event->buffer_activity && allow_buffer(cmd->parms)) { // Buffer write with bogus data, but only once debug_cmd_buffer_write(cmd->dbg_fp, cmd->dbg_id, event->tag); psl_buffer_write(cmd->afu_event, event->tag, event->addr, CACHELINE_BYTES, event->data, event->parity); event->buffer_activity = 1; } else if (client->mem_access == NULL) { // Send read request to client, set client->mem_access // to point to this event blocking any other memory // accesses to client until data is returned by call // to the _handle_mem_read() function. buffer[0] = (uint8_t) PSLSE_MEMORY_READ; buffer[1] = (uint8_t) event->size; addr = (uint64_t *) & (buffer[2]); *addr = htonll(event->addr); event->abort = &(client->abort); if (put_bytes(client->fd, 10, buffer, cmd->dbg_fp, cmd->dbg_id, event->context) < 0) { client_drop(client, PSL_IDLE_CYCLES, CLIENT_NONE); } event->state = MEM_REQUEST; debug_cmd_client(cmd->dbg_fp, cmd->dbg_id, event->tag, event->context); client->mem_access = (void *)event; } }
// Attach to AFU static void _attach(struct psl *psl, struct client *client) { uint64_t wed; uint8_t ack; uint8_t buffer[MAX_LINE_CHARS]; size_t size; // FIXME: This only works for dedicate mode // might work for afu-directed now - lgt // Get wed value from application // always do the get // pass the wed only for dedicated ack = PSLSE_DETACH; size = sizeof(uint64_t); if (get_bytes_silent(client->fd, size, buffer, psl->timeout, &(client->abort)) < 0) { warn_msg("Failed to get WED value from client"); client_drop(client, PSL_IDLE_CYCLES, CLIENT_NONE); goto attach_done; } // but need to save wed if master|slave for future consumption // interestingly, I can always save it // add to client type. memcpy((char *)&wed, (char *)buffer, sizeof(uint64_t)); // wed came over in be format // since we are modeling the psl register here, we should leave it be #if defined PSL9lite || defined PSL9 client->wed = wed; // ntohll(wed); #else client->wed = ntohll(wed); #endif // Send start to AFU // only add PSL_JOB_START for dedicated and master clients. // send an empty wed in the case of master // lgt - new idea: // track number of clients in psl // if number of clients = 0, then add the start job // add llcmd add to client (loop through clients in send_com) // increment number of clients (decrement where we handle the completion of the detach) switch (client->type) { case 'd': if (psl->attached_clients == 0) { if (add_job(psl->job, PSL_JOB_START, client->wed) != NULL) { // if dedicated, we can ack PSLSE_ATTACH // if master, we might want to wait until after the llcmd add is complete // can I wait here for the START to finish? psl->idle_cycles = PSL_IDLE_CYCLES; ack = PSLSE_ATTACH; } } break; case 'm': case 's': if (psl->attached_clients < psl->max_clients) { if (psl->attached_clients == 0) { if (add_job(psl->job, PSL_JOB_START, 0L) != NULL) { // if master, we might want to wait until after the llcmd add is complete // can I wait here for the START to finish? } } psl->idle_cycles = PSL_IDLE_CYCLES; ack = PSLSE_ATTACH; } // running will be set by send/handle_aux2 routines break; default: // error? break; } psl->attached_clients++; info_msg( "Attached client context %d: current attached clients = %d: client type = %c\n", client->context, psl->attached_clients, client->type ); // for master and slave send llcmd add // master "wed" is 0x0005000000000000 can actually use client->context here as well since context = 0 // slave "wed" is 0x000500000000hhhh where hhhh is the "handle" from client->context // now - about those llcmds :-) // put these in a separate list associated with the job? psl->pe maybe... or another call to add_job? // new routine to job.c? add_cmd? // should a slave know their master? if (client->type == 'm' || client->type == 's') { wed = PSL_LLCMD_ADD; wed = wed | (uint64_t)client->context; // add_pe adds to the client if (add_pe(psl->job, PSL_JOB_LLCMD, wed) != NULL) { } } attach_done: if (put_bytes(client->fd, 1, &ack, psl->dbg_fp, psl->dbg_id, client->context) < 0) { client_drop(client, PSL_IDLE_CYCLES, CLIENT_NONE); } }
// Handle events from AFU static void _handle_afu(struct psl *psl) { struct client *client; uint64_t error; uint8_t *buffer; int reset_done; int i; size_t size; reset_done = _handle_aux2(psl, &(psl->parity_enabled), &(psl->latency), &error); //printf("after reset_done in handle_afu \n"); if (error) { if (dedicated_mode_support(psl->mmio)) { client = psl->client[0]; size = 1 + sizeof(uint64_t); buffer = (uint8_t *) malloc(size); buffer[0] = PSLSE_AFU_ERROR; error = htonll(error); memcpy((char *)&(buffer[1]), (char *)&error, sizeof(error)); warn_msg("%s: Received JERROR: 0x%016"PRIx64" in afu-dedicated mode", psl->name, error); if (put_bytes (client->fd, size, buffer, psl->dbg_fp, psl->dbg_id, 0) < 0) { client_drop(client, PSL_IDLE_CYCLES, CLIENT_NONE); } } if (directed_mode_support(psl->mmio)) { // afu error gets logged by OS. - print warning message // no interrupt/event is sent up to the application - don't "put_bytes" back to client(s) // all clients lose connection to afu but how is this observered by the client? warn_msg("%s: Received JERROR: 0x%016"PRIx64" in afu-directed mode", psl->name, error); for (i = 0; i < psl->max_clients; i++) { if (psl->client[i] == NULL) continue; client_drop(psl->client[i], PSL_IDLE_CYCLES, CLIENT_NONE); } } } handle_mmio_ack(psl->mmio, psl->parity_enabled); if (psl->cmd != NULL) { if (reset_done) psl->cmd->credits = psl->cmd->parms->credits; #if defined PSL9lite || defined PSL9 handle_caia2_cmds(psl->cmd); #endif /* ifdef PSL9 or PSL9lite */ #ifdef PSL9 handle_dma0_port(psl->cmd); handle_dma0_write(psl->cmd); handle_dma0_sent_sts(psl->cmd); handle_dma0_read(psl->cmd); #endif /* ifdef PSL9 */ handle_response(psl->cmd); handle_buffer_write(psl->cmd); handle_buffer_read(psl->cmd); handle_buffer_data(psl->cmd, psl->parity_enabled); handle_mem_write(psl->cmd); handle_touch(psl->cmd); handle_cmd(psl->cmd, psl->parity_enabled, psl->latency); handle_interrupt(psl->cmd); } }