📄 l1.c
字号:
while ( counter > 0 ) { writeb(*str, (unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); counter--; str++; } } } else {#endif /* USE_SAL_CONSOLE_IO */ nasid_t nasid = get_master_nasid(); int l1_write(l1sc_t *, char *, int, int); if ( L1_cons_is_inited ) { if ( NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module != (module_t *)0 ) return(l1_write(&NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module->elsc, str, len,#if defined(SYNC_CONSOLE_WRITE) 1#else !L1_interrupts_connected#endif )); } return(early_l1_serial_out(nasid, str, len, NOT_LOCKED));#if defined(USE_SAL_CONSOLE_IO) } } return((counter <= 0) ? 0 : (len - counter));#endif}/* * These are the 'early' functions - when we need to do things before we have * all the structs setup. */static l1sc_t Early_console; /* fake l1sc_t */static int Early_console_inited = 0;static voidearly_brl1_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart ){ int i; brl1_sch_t *subch; bzero( sc, sizeof( *sc ) ); sc->nasid = nasid; sc->uart = uart; sc->getc_f = (uart == BRL1_LOCALHUB_UART ? uart_getc : rtr_uart_getc); sc->putc_f = (uart == BRL1_LOCALHUB_UART ? uart_putc : rtr_uart_putc); sc->sol = 1; subch = sc->subch; /* initialize L1 subchannels */ /* assign processor TTY channels */ for( i = 0; i < CPUS_PER_NODE; i++, subch++ ) { subch->use = BRL1_SUBCH_RSVD; subch->packet_arrived = ATOMIC_INIT(0); subch->tx_notify = NULL; subch->rx_notify = NULL; subch->iqp = &sc->garbage_q; } /* assign system TTY channel (first free subchannel after each * processor's individual TTY channel has been assigned) */ subch->use = BRL1_SUBCH_RSVD; subch->packet_arrived = ATOMIC_INIT(0); subch->tx_notify = NULL; subch->rx_notify = NULL; if( sc->uart == BRL1_LOCALHUB_UART ) { static sc_cq_t x_iqp; subch->iqp = &x_iqp; ASSERT( subch->iqp ); cq_init( subch->iqp ); } else { /* we shouldn't be getting console input from remote UARTs */ subch->iqp = &sc->garbage_q; } subch++; i++; /* "reserved" subchannels (0x05-0x0F); for now, throw away * incoming packets */ for( ; i < 0x10; i++, subch++ ) { subch->use = BRL1_SUBCH_FREE; subch->packet_arrived = ATOMIC_INIT(0); subch->tx_notify = NULL; subch->rx_notify = NULL; subch->iqp = &sc->garbage_q; } /* remaining subchannels are free */ for( ; i < BRL1_NUM_SUBCHANS; i++, subch++ ) { subch->use = BRL1_SUBCH_FREE; subch->packet_arrived = ATOMIC_INIT(0); subch->tx_notify = NULL; subch->rx_notify = NULL; subch->iqp = &sc->garbage_q; }}static inline l1sc_t *early_sc_init(nasid_t nasid){ /* This is for early I/O */ if ( Early_console_inited == 0 ) { early_brl1_init(&Early_console, nasid, BRL1_LOCALHUB_UART); Early_console_inited = 1; } return(&Early_console);}#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) ); \ }static intearly_l1_serial_out( nasid_t nasid, char *str, int len, int lock_state ){ int ret, sent = 0; char *msg = str; static int early_l1_send( nasid_t nasid, char *str, int len, int lock_state ); while ( sent < len ) { ret = early_l1_send(nasid, msg, len - sent, lock_state); sent += ret; msg += ret; } return(len);}static inline intearly_l1_send( nasid_t nasid, char *str, int len, int lock_state ){ int sent; char crc_char; unsigned short crc = INIT_CRC; if( len > (BRL1_QSIZE - 1) ) len = (BRL1_QSIZE - 1); sent = len; if ( lock_state == NOT_LOCKED ) 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 ); if ( lock_state == NOT_LOCKED ) unlock_console(nasid); return sent;}/********************************************************************* * 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_poll( l1sc_t *sc, int mode ){ int ret; /* 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; } ret = brl1_receive( sc, mode ); if ( (ret != BRL1_VALID) && (ret != BRL1_NO_MESSAGE) && (ret != BRL1_PROTOCOL) && (ret != BRL1_CRC) ) L1_collectibles[L1C_REC_STALLS] = ret; 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_getc( l1sc_t *sc, int mode ){ unsigned long pl = 0; int c; brl1_sch_t *subch = &(sc->subch[SC_CONS_SYSTEM]); sc_cq_t *q = subch->iqp; if( !l1_poll( sc, mode ) ) { return 0; } SUBCH_DATA_LOCK( subch, pl ); if( cq_empty( q ) ) { atomic_set(&subch->packet_arrived, 0); SUBCH_DATA_UNLOCK( subch, pl ); return 0; } cq_rem( q, c ); if( cq_empty( q ) ) atomic_set(&subch->packet_arrived, 0); SUBCH_DATA_UNLOCK( subch, pl ); return c;}/* * Write a message to the L1 on the system console subchannel. * * Danger: don't use a non-zero value for the wait parameter unless you're * someone important (like a kernel error message). */intl1_write( l1sc_t *sc, char *msg, int len, int wait ){ int sent = 0, ret = 0; if ( wait ) { while ( sent < len ) { ret = brl1_send( sc, msg, len - sent, (SC_CONS_SYSTEM | BRL1_EVENT), wait ); sent += ret; msg += ret; } ret = len; } else { ret = brl1_send( sc, msg, len, (SC_CONS_SYSTEM | BRL1_EVENT), wait ); } return(ret);}/* initialize the system console subchannel */voidl1_init(void){ /* All we do now is remember that we have been called */ L1_cons_is_inited = 1;}/********************************************************************* * 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( int dummy0, void *dummy1, struct pt_regs *dummy2, l1sc_t *sc, int ch ){ unsigned long pl = 0; brl1_sch_t *subch = &(sc->subch[ch]); SUBCH_DATA_LOCK( subch, pl ); sv_signal( &(subch->arrive_sv) ); SUBCH_DATA_UNLOCK( subch, pl );}/* 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; unsigned long pl = 0; brl1_sch_t *subch; SUBCH_LOCK( sc, pl ); /* 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, pl ); return SC_NSUBCH; } subch->use = BRL1_SUBCH_RSVD; SUBCH_UNLOCK( sc, pl ); 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 = snia_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 ){ unsigned long pl = 0; brl1_sch_t *subch; SUBCH_LOCK( sc, pl ); subch = &(sc->subch[ch]); if( subch->use != BRL1_SUBCH_RSVD ) { /* we're trying to close a subchannel that's not open */ SUBCH_UNLOCK( sc, pl ); return SC_NOPEN; } atomic_set(&subch->packet_arrived, 0); subch->use = BRL1_SUBCH_FREE; sv_broadcast( &(subch->arrive_sv) ); sv_destroy( &(subch->arrive_sv) ); spin_lock_destroy( &(subch->data_lock) ); ASSERT( subch->iqp && (subch->iqp != &sc->garbage_q) ); snia_kmem_free( subch->iqp, sizeof(sc_cq_t) ); subch->iqp = &sc->garbage_q; subch->tx_notify = NULL; subch->rx_notify = brl1_discard_packet; SUBCH_UNLOCK( sc, pl ); 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -