📄 l1.c
字号:
}intl1_control_in(int offset){ nasid_t nasid = 0; //(get_elsc())->nasid; return(READ_L1_UART_REG(nasid, offset)); }#define PUTCHAR(ch) \ { \ while( (!(READ_L1_UART_REG( nasid, REG_LSR ) & LSR_XHRE)) || \ (!(READ_L1_UART_REG( nasid, REG_MSR ) & MSR_CTS)) ); \ WRITE_L1_UART_REG( nasid, REG_DAT, (ch) ); \ }intl1_serial_out( char *str, int len ){ int sent = len; char crc_char; unsigned short crc = INIT_CRC; nasid_t nasid = 0; //(get_elsc())->nasid; lock_console(nasid); PUTCHAR( BRL1_FLAG_CH ); PUTCHAR( BRL1_EVENT | SC_CONS_SYSTEM ); crc = crc16_calc( crc, (BRL1_EVENT | SC_CONS_SYSTEM) ); while( len ) { if( (*str == BRL1_FLAG_CH) || (*str == BRL1_ESC_CH) ) { PUTCHAR( BRL1_ESC_CH ); PUTCHAR( (*str) ^ BRL1_XOR_CH ); } else { PUTCHAR( *str ); } crc = crc16_calc( crc, *str ); str++; len--; } crc ^= 0xffff; crc_char = crc & 0xff; if( (crc_char == BRL1_ESC_CH) || (crc_char == BRL1_FLAG_CH) ) { crc_char ^= BRL1_XOR_CH; PUTCHAR( BRL1_ESC_CH ); } PUTCHAR( crc_char ); crc_char = (crc >> 8) & 0xff; if( (crc_char == BRL1_ESC_CH) || (crc_char == BRL1_FLAG_CH) ) { crc_char ^= BRL1_XOR_CH; PUTCHAR( BRL1_ESC_CH ); } PUTCHAR( crc_char ); PUTCHAR( BRL1_FLAG_CH ); unlock_console(nasid); return sent - len;}intl1_serial_in(void){ static int l1_cons_getc( l1sc_t *sc ); return(l1_cons_getc(get_elsc()));}/********************************************************************* * l1_cons functions * * These allow the L1 to act as the system console. They're intended * to abstract away most of the br/l1 internal details from the * _L1_cons_* functions (in the prom-- see "l1_console.c") and * l1_* functions (in the kernel-- see "sio_l1.c") that they support. * */static intl1_cons_poll( l1sc_t *sc ){ /* in case this gets called before the l1sc_t structure for the module_t * struct for this node is initialized (i.e., if we're called with a * zero l1sc_t pointer)... */ if( !sc ) { return 0; } if( atomic_read(&sc->subch[SC_CONS_SYSTEM].packet_arrived) ) { return 1; } brl1_receive( sc ); if( atomic_read(&sc->subch[SC_CONS_SYSTEM].packet_arrived) ) { return 1; } return 0;}/* pull a character off of the system console queue (if one is available) */static intl1_cons_getc( l1sc_t *sc ){ int c; brl1_sch_t *subch = &(sc->subch[SC_CONS_SYSTEM]); sc_cq_t *q = subch->iqp; if( !l1_cons_poll( sc ) ) { return 0; } SUBCH_DATA_LOCK( subch ); if( cq_empty( q ) ) { atomic_set(&subch->packet_arrived, 0); SUBCH_DATA_UNLOCK( subch ); return 0; } cq_rem( q, c ); if( cq_empty( q ) ) atomic_set(&subch->packet_arrived, 0); SUBCH_DATA_UNLOCK( subch ); return c;}/* initialize the system console subchannel */voidl1_cons_init( l1sc_t *sc ){ brl1_sch_t *subch = &(sc->subch[SC_CONS_SYSTEM]); SUBCH_DATA_LOCK( subch ); atomic_set(&subch->packet_arrived, 0); cq_init( subch->iqp ); SUBCH_DATA_UNLOCK( subch );}/********************************************************************* * The following functions and definitions implement the "message"- * style interface to the L1 system controller. * * Note that throughout this file, "sc" generally stands for "system * controller", while "subchannels" tend to be represented by * variables with names like subch or ch. * */#ifdef L1_DEBUG#define L1_DBG_PRF(x) printf x#else#define L1_DBG_PRF(x)#endif/* sc_data_ready is called to signal threads that are blocked on * l1 input. */voidsc_data_ready( l1sc_t *sc, int ch ){ brl1_sch_t *subch = &(sc->subch[ch]); SUBCH_DATA_LOCK( subch ); sv_signal( &(subch->arrive_sv) ); SUBCH_DATA_UNLOCK( subch );}/* sc_open reserves a subchannel to send a request to the L1 (the * L1's response will arrive on the same channel). The number * returned by sc_open is the system controller subchannel * acquired. */intsc_open( l1sc_t *sc, uint target ){ /* The kernel version implements a locking scheme to arbitrate * subchannel assignment. */ int ch; brl1_sch_t *subch; SUBCH_LOCK( sc ); /* Look for a free subchannel. Subchannels 0-15 are reserved * for other purposes. */ for( subch = &(sc->subch[BRL1_CMD_SUBCH]), ch = BRL1_CMD_SUBCH; ch < BRL1_NUM_SUBCHANS; subch++, ch++ ) { if( subch->use == BRL1_SUBCH_FREE ) break; } if( ch == BRL1_NUM_SUBCHANS ) { /* there were no subchannels available! */ SUBCH_UNLOCK( sc ); return SC_NSUBCH; } subch->use = BRL1_SUBCH_RSVD; SUBCH_UNLOCK( sc ); atomic_set(&subch->packet_arrived, 0); subch->target = target; spin_lock_init( &(subch->data_lock) ); sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */); subch->tx_notify = NULL; subch->rx_notify = sc_data_ready; subch->iqp = kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, NASID_TO_COMPACT_NODEID(sc->nasid) ); ASSERT( subch->iqp ); cq_init( subch->iqp ); return ch;}/* sc_close frees a Bedrock<->L1 subchannel. */intsc_close( l1sc_t *sc, int ch ){ brl1_sch_t *subch; SUBCH_LOCK( sc ); subch = &(sc->subch[ch]); if( subch->use != BRL1_SUBCH_RSVD ) { /* we're trying to close a subchannel that's not open */ return SC_NOPEN; } atomic_set(&subch->packet_arrived, 0); subch->use = BRL1_SUBCH_FREE; SUBCH_DATA_LOCK( subch ); sv_broadcast( &(subch->arrive_sv) ); sv_destroy( &(subch->arrive_sv) ); SUBCH_DATA_UNLOCK( subch ); spin_lock_destroy( &(subch->data_lock) ); ASSERT( subch->iqp && (subch->iqp != &sc->garbage_q) ); kmem_free( subch->iqp, sizeof(sc_cq_t) ); subch->iqp = &sc->garbage_q; SUBCH_UNLOCK( sc ); return SC_SUCCESS;}/* sc_construct_msg builds a bedrock-to-L1 request in the supplied * buffer. Returns the length of the message. The * safest course when passing a buffer to be filled in is to use * BRL1_QSIZE as the buffer size. * * Command arguments are passed as type/argument pairs, i.e., to * pass the number 5 as an argument to an L1 command, call * sc_construct_msg as follows: * * char msg[BRL1_QSIZE]; * msg_len = sc_construct_msg( msg, * BRL1_QSIZE, * target_component, * L1_ADDR_TASK_BOGUSTASK, * L1_BOGUSTASK_REQ_BOGUSREQ, * 2, * L1_ARG_INT, 5 ); * * To pass an additional ASCII argument, you'd do the following: * * char *str; * ... str points to a null-terminated ascii string ... * msg_len = sc_construct_msg( msg, * BRL1_QSIZE, * target_component, * L1_ADDR_TASK_BOGUSTASK, * L1_BOGUSTASK_REQ_BOGUSREQ, * 4, * L1_ARG_INT, 5, * L1_ARG_ASCII, str ); * * Finally, arbitrary data of unknown type is passed using the argtype * code L1_ARG_UNKNOWN, a data length, and a buffer pointer, e.g. * * msg_len = sc_construct_msg( msg, * BRL1_QSIZE, * target_component, * L1_ADDR_TASK_BOGUSTASK, * L1_BOGUSTASK_REQ_BOGUSREQ, * 3, * L1_ARG_UNKNOWN, 32, bufptr ); * * ...passes 32 bytes of data starting at bufptr. Note that no string or * "unknown"-type argument should be long enough to overflow the message * buffer. * * To construct a message for an L1 command that requires no arguments, * you'd use the following: * * msg_len = sc_construct_msg( msg, * BRL1_QSIZE, * target_component, * L1_ADDR_TASK_BOGUSTASK, * L1_BOGUSTASK_REQ_BOGUSREQ, * 0 ); * * The final 0 means "no varargs". Notice that this parameter is used to hold * the number of additional arguments to sc_construct_msg, _not_ the actual * number of arguments used by the L1 command (so 2 per L1_ARG_[INT,ASCII] * type argument, and 3 per L1_ARG_UNKOWN type argument). A call to construct * an L1 command which required three integer arguments and two arguments of * some arbitrary (unknown) type would pass 12 as the value for this parameter. * * ENDIANNESS WARNING: The following code does a lot of copying back-and-forth * between byte arrays and four-byte big-endian integers. Depending on the * system controller connection and endianness of future architectures, some * rewriting might be necessary. */intsc_construct_msg( l1sc_t *sc, /* system controller struct */ int ch, /* subchannel for this message */ char *msg, /* message buffer */ int msg_len, /* size of message buffer */ l1addr_t addr_task, /* target system controller task */ short req_code, /* 16-bit request code */ int req_nargs, /* # of arguments (varargs) passed */ ... ) /* any additional parameters */{ uint32_t buf32; /* 32-bit buffer used to bounce things around */ void *bufptr; /* used to hold command argument addresses */ va_list al; /* variable argument list */ int index; /* current index into msg buffer */ int argno; /* current position in varargs list */ int l1_argno; /* running total of arguments to l1 */ int l1_arg_t; /* argument type/length */ int l1_argno_byte; /* offset of argument count byte */ index = argno = 0; /* set up destination address */ if( (msg_len -= sizeof( buf32 )) < 0 ) return -1; L1_ADDRESS_TO_TASK( &buf32, sc->subch[ch].target, addr_task ); COPY_INT_TO_BUFFER(msg, index, buf32); /* copy request code */ if( (msg_len -= 2) < 0 ) return( -1 ); msg[index++] = ((req_code >> 8) & 0xff); msg[index++] = (req_code & 0xff); if( !req_nargs ) { return index; } /* reserve a byte for the argument count */ if( (msg_len -= 1) < 0 ) return( -1 ); l1_argno_byte = index++; l1_argno = 0; /* copy additional arguments */ va_start( al, req_nargs ); while( argno < req_nargs ) { l1_argno++; l1_arg_t = va_arg( al, int ); argno++; switch( l1_arg_t ) { case L1_ARG_INT: if( (msg_len -= (sizeof( buf32 ) + 1)) < 0 ) return( -1 ); msg[index++] = L1_ARG_INT; buf32 = (unsigned)va_arg( al, int ); argno++; COPY_INT_TO_BUFFER(msg, index, buf32); break; case L1_ARG_ASCII: bufptr = va_arg( al, char* ); argno++; if( (msg_len -= (strlen( bufptr ) + 2)) < 0 ) return( -1 ); msg[index++] = L1_ARG_ASCII; strcpy( (char *)&(msg[index]), (char *)bufptr ); index += (strlen( bufptr ) + 1); /* include terminating null */ break; case L1_ARG_UNKNOWN: { int arglen; arglen = va_arg( al, int ); argno++; bufptr = va_arg( al, void* ); argno++; if( (msg_len -= (arglen + 1)) < 0 ) return( -1 ); msg[index++] = L1_ARG_UNKNOWN | arglen; BCOPY( bufptr, &(msg[index]), arglen ); index += arglen; break; } default: /* unhandled argument type */ return -1; } } va_end( al ); msg[l1_argno_byte] = l1_argno; return index;}/* sc_interpret_resp verifies an L1 response to a bedrock request, and * breaks the response data up into the constituent parts. If the * response message indicates error, or if a mismatch is found in the * expected number and type of arguments, an error is returned. The * arguments to this function work very much like the arguments to * sc_construct_msg, above, except that L1_ARG_INTs must be followed * by a _pointer_ to an integer that can be filled in by this function. */intsc_interpret_resp( char *resp, /* buffer received from L1 */ int resp_nargs, /* number of _varargs_ passed in */ ... ){ uint32_t buf32; /* 32-bit buffer used to bounce things around */ void *bufptr; /* used to hold response field addresses */ va_list al; /* variable argument list */ int index; /* current index into response buffer */ int argno; /* current position in varargs list */ int l1_fldno; /* number of resp fields received from l1 */ int l1_fld_t; /* field type/length */ index = argno = 0;#if defined(L1_DEBUG)#define DUMP_RESP \ { \ int ix; \ char outbuf[512]; \ sprintf( outbuf, "sc_interpret_resp error line %d: ", __LINE__ ); \ for( ix = 0; ix < 16; ix++ ) { \ sprintf( &outbuf[strlen(outbuf)], "%x ", resp[ix] ); \ } \ printk( "%s\n", outbuf ); \ }#else#define DUMP_RESP#endif /* L1_DEBUG */ /* check response code */ COPY_BUFFER_TO_INT(resp, index, buf32); if( buf32 != L1_RESP_OK ) { DUMP_RESP; return buf32; } /* get number of response fields */ l1_fldno = resp[index++]; va_start( al, resp_nargs ); /* copy out response fields */ while( argno < resp_nargs ) { l1_fldno--; l1_fld_t = va_arg( al, int ); argno++; switch( l1_fld_t ) { case L1_ARG_INT: if( resp[index++] != L1_ARG_INT ) { /* type mismatch */ va_end( al ); DUMP_RESP; return -1; } bufptr = va_arg( al, int* ); argno++; COPY_BUFFER_TO_BUFFER(resp, index, bufptr); break; case L1_ARG_ASCII: if( resp[index++] != L1_ARG_ASCII ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -