// Associate client to PSL static int _client_associate(struct client *client, uint8_t id, char afu_type) { struct psl *psl; uint32_t mmio_offset, mmio_size; uint8_t major, minor; int i, context, clients; uint8_t rc[2]; // Associate with PSL rc[0] = PSLSE_DETACH; psl = _find_psl(id, &major, &minor); if (!psl) { info_msg("Did not find valid PSL for afu%d.%d\n", major, minor); put_bytes(client->fd, 1, &(rc[0]), fp, -1, -1); close_socket(&(client->fd)); return -1; } // Check AFU type is valid for connection switch (afu_type) { case 'd': if (!dedicated_mode_support(psl->mmio)) { warn_msg ("afu%d.%d is does not support dedicated mode\n", major, minor); put_bytes(client->fd, 1, &(rc[0]), fp, psl->dbg_id, -1); close_socket(&(client->fd)); return -1; } break; case 'm': case 's': if (!directed_mode_support(psl->mmio)) { warn_msg("afu%d.%d is does not support directed mode\n", major, minor); put_bytes(client->fd, 1, &(rc[0]), fp, psl->dbg_id, -1); close_socket(&(client->fd)); return -1; } break; default: warn_msg("AFU device type '%c' is not valid\n", afu_type); put_bytes(client->fd, 1, &(rc[0]), fp, psl->dbg_id, -1); close_socket(&(client->fd)); return -1; } // check to see if device is already open // lgt - I think I can open any combination of m/s upto max if ( afu_type == 'd' /* | afu_type == 'm' */ ) { if (psl->client[0] != NULL) { warn_msg ("afu%d.%d%c is already open\n", major, minor, afu_type); put_bytes(client->fd, 1, &(rc[0]), fp, psl->dbg_id, -1); // should I really close the socket in this case? close_socket(&(client->fd)); return -1; } } // Look for open client slot // dedicated - client[0] is the only client. // afu-directed - is client[0] the master? not necessarily assert(psl->max_clients > 0); clients = 0; context = -1; for (i = 0; i < psl->max_clients; i++) { if (psl->client[i] != NULL) ++clients; if ((context < 0) && (psl->client[i] == NULL)) { client->context = context = i; client->state = CLIENT_VALID; client->pending = 0; psl->client[i] = client; break; } } if (context < 0) { info_msg("No room for new client on afu%d.%d\n", major, minor); put_bytes(client->fd, 1, &(rc[0]), fp, psl->dbg_id, -1); close_socket(&(client->fd)); return -1; } // Attach to PSL // i should point to an open slot rc[0] = PSLSE_OPEN; rc[1] = context; mmio_offset = 0; if (psl->mmio->desc.PerProcessPSA & PROCESS_PSA_REQUIRED) { mmio_size = psl->mmio->desc.PerProcessPSA & PSA_MASK; mmio_size *= FOUR_K; mmio_offset = psl->mmio->desc.PerProcessPSA_offset; mmio_offset += mmio_size * i; } else { mmio_size = MMIO_FULL_RANGE; } client->mmio_size = mmio_size; client->mmio_offset = mmio_offset; client->max_irqs = PSL_MAX_IRQS / psl->mmio->desc.num_of_processes; client->type = afu_type; // Send reset to AFU, if no other clients already connected // hmmm... this might be a problem... // I need only do this on the very first client in m/s mode... // if this is dedicated client (only one), send a reset // if this an an afu-directed client, only send a reset on the very first open... // don't even send a reset if we've dropped to 0 clients and are now opening a new one switch ( afu_type ) { case 'd': // send a reset debug_msg( "_client_associate: adding reset for open of dedicated device", afu_type ); add_job(psl->job, PSL_JOB_RESET, 0L); // ignores psl->has_been_reset break; case 'm': case 's': // send a reset the very first time we associate a client if ( psl->has_been_reset == 0 ) { debug_msg( "_client_associate: adding reset for first open of afu-directed device", afu_type ); add_job(psl->job, PSL_JOB_RESET, 0L); psl->has_been_reset = 1; } break; default: debug_msg( "_client_associate: invalid afu_type: %c", afu_type ); } // Acknowledge to client if (put_bytes(client->fd, 2, &(rc[0]), fp, psl->dbg_id, context) < 0) { close_socket(&(client->fd)); return -1; } debug_context_add(fp, psl->dbg_id, context); return 0; }
// Initialize and start PSL thread // // The return value is encode int a 16-bit value divided into 4 for each // possible adapter. Then the 4 bits in each adapter represent the 4 possible // AFUs on an adapter. For example: afu0.0 is 0x8000 and afu3.0 is 0x0008. uint16_t psl_init(struct psl **head, struct parms *parms, char *id, char *host, int port, pthread_mutex_t * lock, FILE * dbg_fp) { struct psl *psl; struct job_event *reset; uint16_t location; location = 0x8000; if ((psl = (struct psl *)calloc(1, sizeof(struct psl))) == NULL) { perror("malloc"); error_msg("Unable to allocation memory for psl"); goto init_fail; } psl->timeout = parms->timeout; if ((strlen(id) != 6) || strncmp(id, "afu", 3) || (id[4] != '.')) { warn_msg("Invalid afu name: %s", id); goto init_fail; } if ((id[3] < '0') || (id[3] > '3')) { warn_msg("Invalid afu major: %c", id[3]); goto init_fail; } if ((id[5] < '0') || (id[5] > '3')) { warn_msg("Invalid afu minor: %c", id[5]); goto init_fail; } psl->dbg_fp = dbg_fp; psl->major = id[3] - '0'; psl->minor = id[5] - '0'; psl->dbg_id = psl->major << 4; psl->dbg_id |= psl->minor; location >>= (4 * psl->major); location >>= psl->minor; if ((psl->name = (char *)malloc(strlen(id) + 1)) == NULL) { perror("malloc"); error_msg("Unable to allocation memory for psl->name"); goto init_fail; } strcpy(psl->name, id); if ((psl->host = (char *)malloc(strlen(host) + 1)) == NULL) { perror("malloc"); error_msg("Unable to allocation memory for psl->host"); goto init_fail; } strcpy(psl->host, host); psl->port = port; psl->client = NULL; psl->idle_cycles = PSL_IDLE_CYCLES; psl->lock = lock; // Connect to AFU psl->afu_event = (struct AFU_EVENT *)malloc(sizeof(struct AFU_EVENT)); if (psl->afu_event == NULL) { perror("malloc"); goto init_fail; } info_msg("Attempting to connect AFU: %s @ %s:%d", psl->name, psl->host, psl->port); if (psl_init_afu_event(psl->afu_event, psl->host, psl->port) != PSL_SUCCESS) { warn_msg("Unable to connect AFU: %s @ %s:%d", psl->name, psl->host, psl->port); goto init_fail; } // DEBUG debug_afu_connect(psl->dbg_fp, psl->dbg_id); // Initialize job handler if ((psl->job = job_init(psl->afu_event, &(psl->state), psl->name, psl->dbg_fp, psl->dbg_id)) == NULL) { perror("job_init"); goto init_fail; } // Initialize mmio handler if ((psl->mmio = mmio_init(psl->afu_event, psl->timeout, psl->name, psl->dbg_fp, psl->dbg_id)) == NULL) { perror("mmio_init"); goto init_fail; } // Initialize cmd handler if ((psl->cmd = cmd_init(psl->afu_event, parms, psl->mmio, &(psl->state), psl->name, psl->dbg_fp, psl->dbg_id)) == NULL) { perror("cmd_init"); goto init_fail; } // Set credits for AFU if (psl_aux1_change(psl->afu_event, psl->cmd->credits) != PSL_SUCCESS) { warn_msg("Unable to set credits"); goto init_fail; } // Start psl loop thread if (pthread_create(&(psl->thread), NULL, _psl_loop, psl)) { perror("pthread_create"); goto init_fail; } // Add psl to list while ((*head != NULL) && ((*head)->major < psl->major)) { head = &((*head)->_next); } while ((*head != NULL) && ((*head)->major == psl->major) && ((*head)->minor < psl->minor)) { head = &((*head)->_next); } psl->_next = *head; if (psl->_next != NULL) psl->_next->_prev = psl; *head = psl; // Send reset to AFU reset = add_job(psl->job, PSL_JOB_RESET, 0L); while (psl->job->job == reset) { /*infinite loop */ lock_delay(psl->lock); } // Read AFU descriptor psl->state = PSLSE_DESC; read_descriptor(psl->mmio, psl->lock); // Finish PSL configuration psl->state = PSLSE_IDLE; if (dedicated_mode_support(psl->mmio)) { // AFU supports Dedicated Mode psl->max_clients = 1; } if (directed_mode_support(psl->mmio)) { // AFU supports Directed Mode psl->max_clients = psl->mmio->desc.num_of_processes; } if (psl->max_clients == 0) { error_msg("AFU programming model is invalid"); goto init_fail; } psl->client = (struct client **)calloc(psl->max_clients, sizeof(struct client *)); psl->cmd->client = psl->client; psl->cmd->max_clients = psl->max_clients; return location; init_fail: if (psl) { if (psl->afu_event) { psl_close_afu_event(psl->afu_event); free(psl->afu_event); } if (psl->host) free(psl->host); if (psl->name) free(psl->name); free(psl); } pthread_mutex_unlock(lock); return 0; }
// 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); } }