static void buffer_event (int rnw, uint32_t tag, uint8_t *addr) { uint8_t par[2]; if (status.psl_state==PSL_FLUSHING) { #ifdef DEBUG printf ("Response FLUSHED tag=0x%02x\n", tag); #endif /* #ifdef DEBUG */ add_resp (tag, PSL_RESPONSE_FLUSHED); return; } if (!testmemaddr (addr)) { printf ("AFU attempted "); if (rnw) printf ("write"); else printf ("read"); printf (" to invalid address 0x%016llx\n",(long long) addr); #ifdef DEBUG printf ("Response AERROR tag=0x%02x\n", tag); #endif /* #ifdef DEBUG */ add_resp (tag, PSL_RESPONSE_AERROR); status.psl_state = PSL_FLUSHING; return; } if (rnw) { #ifdef DEBUG printf ("Buffer Read tag=0x%02x\n", tag); #endif /* #ifdef DEBUG */ psl_buffer_read (status.event, tag, (uint64_t) addr, CACHELINE_BYTES); } else { #ifdef DEBUG printf ("Buffer Write tag=0x%02x\n", tag); #endif /* #ifdef DEBUG */ generate_cl_parity(addr, par); psl_buffer_write (status.event, tag, (uint64_t) addr, CACHELINE_BYTES, addr, par); ++status.credits; #ifdef DEBUG printf ("Response tag=0x%02x\n", tag); #endif /* #ifdef DEBUG */ if (status.psl_state==PSL_NLOCK) { #ifdef DEBUG printf ("Nlock response for read, tag=0x%02x\n", tag); fflush (stdout); #endif /* #ifdef DEBUG */ add_resp (tag, PSL_RESPONSE_NLOCK); } else if (!PAGED_RANDOMIZER || (rand() % PAGED_RANDOMIZER)) { // Inject random "Paged" response add_resp (tag, PSL_RESPONSE_DONE); } else { add_resp (tag, PSL_RESPONSE_PAGED); status.psl_state = PSL_FLUSHING; } } }
// 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; } }