1
0
Files
irix-657m-src/stand/arcs/lib/libkl/ml/vector.c
2022-09-29 17:59:04 +03:00

498 lines
12 KiB
C

#include <sys/types.h>
#include <sys/cpu.h>
#include <sys/mips_addrspace.h>
#include <sys/SN/SN0/IP27.h>
#include <sys/SN/vector.h>
#include <sys/SN/agent.h>
#ifndef _STANDALONE
#include <hub.h>
#include <sys/systm.h>
#else
#include <libsk.h>
#include <rtc.h>
#endif
/* TRACE is for simulation. For now, just undefine it. */
#define TRACE(x)
extern int hub_cpu_get(void);
/*
* vector_write_node
*
* Writes a value to a remote hub NI or router register.
* Waits for the response before continuing.
*
* Performs retries because when vector traffic is very
* heavy, routers may drop some requests/responses.
*
* Returns 0 for success, or a negative value for failure.
*/
int
vector_write_node(net_vec_t dest, nasid_t nasid,
int write_id, int address,
__uint64_t value)
{
__uint64_t status;
int try, polls;
int r;
hubreg_t age_regaddr;
hubreg_t age_oldval;
hubreg_t age_newval;
r = 0;
#ifdef _STANDALONE
age_regaddr = ( hub_cpu_get() ) ? NI_AGE_CPU1_MEMORY : NI_AGE_CPU0_MEMORY;
#else
age_regaddr = ( private.p_slice ) ? NI_AGE_CPU1_MEMORY : NI_AGE_CPU0_MEMORY;
#endif
age_oldval = REMOTE_HUB_L(nasid, age_regaddr);
age_newval = (age_oldval & ~NAGE_VCH_MASK) | (VCHANNEL_B << NAGE_VCH_SHFT);
for (try = 0; try < VEC_RETRIES_W; try++) {
REMOTE_HUB_L(nasid, NI_VECTOR_CLEAR);
if (REMOTE_HUB_L(nasid, NI_VECTOR_STATUS) & NVS_VALID) {
r = NET_ERROR_HARDWARE;
goto done;
}
REMOTE_HUB_S(nasid, NI_VECTOR_DATA, value);
REMOTE_HUB_S(nasid, NI_VECTOR, dest);
/* Workaround the router bug...
make all vector operations use VCHANNEL_B
*/
REMOTE_HUB_S(nasid, age_regaddr, age_newval);
REMOTE_HUB_S(nasid, NI_VECTOR_PARMS,
123L << NVP_PIOID_SHFT | /* Unique PIO ID number */
(__uint64_t) write_id << NVP_WRITEID_SHFT |
address & NVP_ADDRESS_MASK |
PIOTYPE_WRITE);
/*
* Revert back to old mode of virtual channel usage.
*/
REMOTE_HUB_S(nasid, age_regaddr, age_oldval);
for (polls = 0; polls < VEC_POLLS_W; polls++) {
#ifndef _STANDALONE
us_delay(1000);
#else
inst_loop_delay(1000);
#endif
status = REMOTE_HUB_L(nasid, NI_VECTOR_STATUS);
if (status & NVS_VALID)
break;
}
if (polls == VEC_POLLS_W)
continue; /* Timed out; retry */
if (status & NVS_OVERRUN) { /* Overrun; retry */
r = NET_ERROR_OVERRUN;
continue;
}
switch (status & NVS_TYPE_MASK) {
case PIOTYPE_ADDR_ERR:
return NET_ERROR_ADDRESS;
case PIOTYPE_CMD_ERR:
return NET_ERROR_COMMAND;
case PIOTYPE_PROT_ERR:
return NET_ERROR_PROT;
case PIOTYPE_WRITE:
break;
default:
return NET_ERROR_REPLY;
}
if ((status & NVS_PIOID_MASK) >> NVS_PIOID_SHFT != 123 ||
(status & NVS_WRITEID_MASK) >> NVS_WRITEID_SHFT != write_id ||
(status & NVS_ADDRESS_MASK) != (address & NVP_ADDRESS_MASK)) {
r = NET_ERROR_REPLY; /* Fatal */
goto done;
}
break; /* Success */
}
if (try == VEC_RETRIES_W) {
r = NET_ERROR_TIMEOUT;
goto done;
}
done:
return r;
}
/*
* vector_read_node
*
* Reads a value from a remote hub NI or router register.
* Waits for the response before continuing.
*
* Performs retries because when vector traffic is very
* heavy, routers may drop some requests/responses.
*
* Returns 0 for success, or a negative value for failure.
*/
int
vector_read_node(net_vec_t dest, nasid_t nasid,
int write_id, int address,
__uint64_t *value)
{
__uint64_t status;
int try, polls;
int r;
hubreg_t age_regaddr;
hubreg_t age_oldval;
hubreg_t age_newval;
r = 0;
#ifdef _STANDALONE
age_regaddr = ( hub_cpu_get() ) ? NI_AGE_CPU1_MEMORY : NI_AGE_CPU0_MEMORY;
#else
age_regaddr = ( private.p_slice ) ? NI_AGE_CPU1_MEMORY : NI_AGE_CPU0_MEMORY;
#endif
age_oldval = REMOTE_HUB_L(nasid, age_regaddr);
age_newval = (age_oldval & ~NAGE_VCH_MASK) | (VCHANNEL_B << NAGE_VCH_SHFT);
for (try = 0; try < VEC_RETRIES_R; try++) {
REMOTE_HUB_L(nasid, NI_VECTOR_CLEAR);
if (REMOTE_HUB_L(nasid, NI_VECTOR_STATUS) & NVS_VALID) {
r = NET_ERROR_HARDWARE;
goto done;
}
#if 1
REMOTE_HUB_S(nasid, NI_VECTOR_READ_DATA, 0xdeadbeefdeadbeef);
#endif
REMOTE_HUB_S(nasid, NI_VECTOR, dest);
/*
* router bug workaround
*/
REMOTE_HUB_S(nasid, age_regaddr, age_newval);
REMOTE_HUB_S(nasid, NI_VECTOR_PARMS,
456L << NVP_PIOID_SHFT | /* Unique PIO ID number */
(__uint64_t) write_id << NVP_WRITEID_SHFT |
address & NVP_ADDRESS_MASK |
PIOTYPE_READ);
/*
* Revert back to old mode of virtual channel usage.
*/
REMOTE_HUB_S(nasid, age_regaddr, age_oldval);
for (polls = 0; polls < VEC_POLLS_R; polls++) {
status = REMOTE_HUB_L(nasid, NI_VECTOR_STATUS);
if (status & NVS_VALID)
break;
}
if (polls == VEC_POLLS_R)
continue; /* Timed out; retry */
if (status & NVS_OVERRUN) {
r = NET_ERROR_OVERRUN;
goto done;
}
switch (status & NVS_TYPE_MASK) {
case PIOTYPE_ADDR_ERR:
return NET_ERROR_ADDRESS;
case PIOTYPE_CMD_ERR:
return NET_ERROR_COMMAND;
case PIOTYPE_PROT_ERR:
return NET_ERROR_PROT;
case PIOTYPE_READ:
break;
default:
return NET_ERROR_REPLY;
}
if ((status & NVS_PIOID_MASK) >> NVS_PIOID_SHFT != 456 ||
(status & NVS_WRITEID_MASK) >> NVS_WRITEID_SHFT != write_id ||
(status & NVS_ADDRESS_MASK) != (address & NVP_ADDRESS_MASK)) {
r = NET_ERROR_REPLY; /* Fatal */
goto done;
}
*value = REMOTE_HUB_L(nasid, NI_VECTOR_READ_DATA);
break; /* Success */
}
if (try == VEC_RETRIES_R) {
r = NET_ERROR_TIMEOUT;
goto done;
}
done:
return r;
}
/*
* vector_exch_node
*
* Conditionally and atomically writes a value into a remote hub NI
* or router register, provided that the current content of the
* register is zero, and returns the value of the register prior to
* the exchange. Waits for the response before continuing.
*
* The value written is intended to be an ID to identify the locker
* when the scratch registers are being used for router locking.
*
* Performs retries because when vector traffic is very
* heavy, routers may drop some requests/responses.
*
* The caller should check the returned value. If it's either zero
* or the requested value, then the lock will have been obtained.
* (It could equal the requested ID if a response was lost and the
* exchange was retried).
*
* Returns 0 for success, or a negative value for failure.
*/
int
vector_exch_node(net_vec_t dest, nasid_t nasid,
int write_id, int address,
__uint64_t *value)
{
__uint64_t status;
int try, polls;
int r;
hubreg_t age_regaddr;
hubreg_t age_oldval;
hubreg_t age_newval;
TRACE(write_id);
TRACE(dest);
TRACE(address);
TRACE(value);
r = 0;
#ifdef _STANDALONE
age_regaddr = ( hub_cpu_get() ) ? NI_AGE_CPU1_MEMORY : NI_AGE_CPU0_MEMORY;
#else
age_regaddr = ( private.p_slice ) ? NI_AGE_CPU1_MEMORY : NI_AGE_CPU0_MEMORY;
#endif
age_oldval = REMOTE_HUB_L(nasid, age_regaddr);
age_newval = (age_oldval & ~NAGE_VCH_MASK) | (VCHANNEL_B << NAGE_VCH_SHFT);
for (try = 0; try < VEC_RETRIES_X; try++) {
REMOTE_HUB_L(nasid, NI_VECTOR_CLEAR);
if (REMOTE_HUB_L(nasid, NI_VECTOR_STATUS) & NVS_VALID) {
r = NET_ERROR_HARDWARE;
goto done;
}
REMOTE_HUB_S(nasid, NI_VECTOR_READ_DATA, 0xdeadbeefdeadbeef);
REMOTE_HUB_S(nasid, NI_VECTOR_DATA, *value);
REMOTE_HUB_S(nasid, NI_VECTOR, dest);
/*
* In order to workaround a router bug, we need to
* make all craylink traffic go on VCHANNEL_A normally, and only
* Vector operations to go on VCHANNEL_B.
* First part is done when the system boots. As part
* of doing the vector operation, change the PI_CPUx_MEMORY to
* point to B instead of A, launch the Vector operation, and
* change it back to A.
*/
REMOTE_HUB_S(nasid, age_regaddr, age_newval);
REMOTE_HUB_S(nasid, NI_VECTOR_PARMS,
789L << NVP_PIOID_SHFT | /* Unique PIO ID number */
(__uint64_t) write_id << NVP_WRITEID_SHFT |
address & NVP_ADDRESS_MASK |
PIOTYPE_EXCHANGE);
/*
* Revert back to old mode of virtual channel usage.
*/
REMOTE_HUB_S(nasid, age_regaddr, age_oldval);
for (polls = 0; polls < VEC_POLLS_X; polls++) {
status = REMOTE_HUB_L(nasid, NI_VECTOR_STATUS);
if (status & NVS_VALID)
break;
}
if (polls == VEC_POLLS_X)
continue; /* Timed out; retry */
if (status & NVS_OVERRUN) {
r = NET_ERROR_OVERRUN;
goto done;
}
switch (status & NVS_TYPE_MASK) {
case PIOTYPE_ADDR_ERR:
return NET_ERROR_ADDRESS;
case PIOTYPE_CMD_ERR:
return NET_ERROR_COMMAND;
case PIOTYPE_PROT_ERR:
return NET_ERROR_PROT;
case PIOTYPE_EXCHANGE:
break;
default:
return NET_ERROR_REPLY;
}
if ((status & NVS_PIOID_MASK) >> NVS_PIOID_SHFT != 789 ||
(status & NVS_WRITEID_MASK) >> NVS_WRITEID_SHFT != write_id ||
(status & NVS_ADDRESS_MASK) != (address & NVP_ADDRESS_MASK)) {
r = NET_ERROR_REPLY; /* Fatal */
goto done;
}
*value = REMOTE_HUB_L(nasid, NI_VECTOR_READ_DATA);
break; /* Success */
}
if (try == VEC_RETRIES_X) {
r = NET_ERROR_TIMEOUT;
goto done;
}
done:
TRACE(r);
return r;
}
/* Same as vector_read_node but for the local node. */
int
vector_read(net_vec_t dest, int write_id, int address, __uint64_t *value)
{
return vector_read_node(dest, get_nasid(), write_id, address, value);
}
/* Same as vector_write_node but for the local node. */
int
vector_write(net_vec_t dest, int write_id, int address, __uint64_t value)
{
return vector_write_node(dest, get_nasid(), write_id, address, value);
}
/* Same as vector_exch_node but for the local node. */
int
vector_exch(net_vec_t dest, int write_id, int address, __uint64_t *value)
{
return vector_exch_node(dest, get_nasid(), write_id, address, value);
}
/*
* Routines for performing simple operations on network vectors
*/
int
vector_length(net_vec_t vec)
{
int len;
for (len = 0; vec & 0xfULL << 4 * len; len++)
;
return len;
}
net_vec_t
vector_get(net_vec_t vec, int n)
{
return vec >> n * 4 & 0xfULL;
}
net_vec_t
vector_prefix(net_vec_t vec, int n)
{
return n ? vec & ~0ULL >> 64 - 4 * n : 0;
}
net_vec_t
vector_modify(net_vec_t entry, int n, int route)
{
return entry & ~(0xfULL << 4 * n) | (net_vec_t) route << 4 * n;
}
net_vec_t
vector_reverse(net_vec_t vec)
{
net_vec_t result;
for (result = 0; vec; vec >>= 4)
result = result << 4 | vec & 0xfULL;
return result;
}
net_vec_t
vector_concat(net_vec_t vec1, net_vec_t vec2)
{
return vec1 | vec2 << 4 * vector_length(vec1);
}
/*
* net_errmsg
*
* Translates an NET_ERROR_code into an appropriate message string.
*/
char
*net_errmsg(int rc)
{
switch (rc) {
case NET_ERROR_NONE:
return "No error";
case NET_ERROR_HARDWARE:
return "Hardware error";
case NET_ERROR_OVERRUN:
return "Extra response(s)";
case NET_ERROR_REPLY:
return "Reply parameters mismatch";
case NET_ERROR_ADDRESS:
return "Address error response";
case NET_ERROR_COMMAND:
return "Command error response";
case NET_ERROR_PROT:
return "Protection error response";
case NET_ERROR_TIMEOUT:
return "Vector response timeout";
case NET_ERROR_VECTOR:
return "Invalid vector";
case NET_ERROR_ROUTERLOCK:
return "Timed out locking router";
default:
return "Undefined error code";
}
}