?? l1.c
字號:
/* some error in UART */ if( *c < 0 ) { *result = BRL1_LINK; return 0; } /* everything's fine */ *result = BRL1_VALID; return 1;}/* * brl1_receive * * This function reads a Bedrock-L1 protocol packet into the l1sc_t * response buffer. * * The operation of this function can be expressed as a finite state * machine: *START STATE INPUT TRANSITION==========================================================BRL1_IDLE (reset or error) flag BRL1_FLAG other BRL1_IDLE@BRL1_FLAG (saw a flag (0x7e)) flag BRL1_FLAG escape BRL1_IDLE@ header byte BRL1_HDR other BRL1_IDLE@BRL1_HDR (saw a type/subch byte)(see below) BRL1_BODY BRL1_HDRBRL1_BODY (reading packet body) flag BRL1_FLAG escape BRL1_ESC other BRL1_BODYBRL1_ESC (saw an escape (0x7d)) flag BRL1_FLAG@ escape BRL1_IDLE@ other BRL1_BODY=========================================================="@" denotes an error transition. * The BRL1_HDR state is a transient state which doesn't read input, * but just provides a way in to code which decides to whom an * incoming packet should be directed. * * brl1_receive can be used to poll for input from the L1, or as * an interrupt service routine. It reads as much data as is * ready from the junk bus UART and places into the appropriate * input queues according to subchannel. The header byte is * stripped from console-type data, but is retained for message- * type data (L1 responses). A length byte will also be * prepended to message-type packets. * * This routine is non-blocking; if the caller needs to block * for input, it must call brl1_receive in a loop. * * brl1_receive returns when there is no more input, the queue * for the current incoming message is full, or there is an * error (parity error, bad header, bad CRC, etc.). */#define STATE_SET(l,s) ((l)->brl1_state = (s))#define STATE_GET(l) ((l)->brl1_state)#define LAST_HDR_SET(l,h) ((l)->brl1_last_hdr = (h))#define LAST_HDR_GET(l) ((l)->brl1_last_hdr)#define SEQSTAMP_INCR(l)#define SEQSTAMP_GET(l)#define VALID_HDR(c) \ ( SUBCH((c)) <= SC_CONS_SYSTEM \ ? PKT_TYPE((c)) == BRL1_REQUEST \ : ( PKT_TYPE((c)) == BRL1_RESPONSE || \ PKT_TYPE((c)) == BRL1_EVENT ) )#define IS_TTY_PKT(l) \ ( SUBCH(LAST_HDR_GET(l)) <= SC_CONS_SYSTEM ? 1 : 0 )intbrl1_receive( l1sc_t *sc ){ int result; /* value to be returned by brl1_receive */ int c; /* most-recently-read character */ int done; /* set done to break out of recv loop */ sc_cq_t *q; /* pointer to queue we're working with */ result = BRL1_NO_MESSAGE;#ifdef FORCE_CONSOLE_NASID sc->nasid = 0;#endif if ( sc->uart == BRL1_LOCALUART ) lock_console(sc->nasid); done = 0; while( !done ) { switch( STATE_GET(sc) ) { case BRL1_IDLE: /* Initial or error state. Waiting for a flag character * to resynchronize with the L1. */ if( !read_uart( sc, &c, &result ) ) { /* error reading uart */ done = 1; continue; } if( c == BRL1_FLAG_CH ) { /* saw a flag character */ STATE_SET( sc, BRL1_FLAG ); continue; } break; case BRL1_FLAG: /* One or more flag characters have been read; look for * the beginning of a packet (header byte). */ if( !read_uart( sc, &c, &result ) ) { /* error reading uart */ if( c != UART_NO_CHAR ) STATE_SET( sc, BRL1_IDLE ); done = 1; continue; } if( c == BRL1_FLAG_CH ) { /* multiple flags are OK */ continue; } if( !VALID_HDR( c ) ) { /* if c isn't a flag it should have been * a valid header, so we have an error */ result = BRL1_PROTOCOL; STATE_SET( sc, BRL1_IDLE ); done = 1; continue; } /* we have a valid header byte */ LAST_HDR_SET( sc, c ); STATE_SET( sc, BRL1_HDR ); break; case BRL1_HDR: /* A header byte has been read. Do some bookkeeping. */ q = sc->subch[ SUBCH( LAST_HDR_GET(sc) ) ].iqp; ASSERT(q); if( !IS_TTY_PKT(sc) ) { /* if this is an event or command response rather * than console I/O, we need to reserve a couple * of extra spaces in the queue for the header * byte and a length byte; if we can't, stay in * the BRL1_HDR state. */ if( cq_room( q ) < 2 ) { result = BRL1_FULL_Q; done = 1; continue; } cq_tent_add( q, 0 ); /* reserve length byte */ cq_tent_add( q, LAST_HDR_GET( sc ) ); /* record header byte */ } STATE_SET( sc, BRL1_BODY ); break; case BRL1_BODY: /* A header byte has been read. We are now attempting * to receive the packet body. */ q = sc->subch[ SUBCH( LAST_HDR_GET(sc) ) ].iqp; ASSERT(q); /* if the queue we want to write into is full, don't read from * the uart (this provides backpressure to the L1 side) */ if( cq_tent_full( q ) ) { result = BRL1_FULL_Q; done = 1; continue; } if( !read_uart( sc, &c, &result ) ) { /* error reading uart */ if( c != UART_NO_CHAR ) STATE_SET( sc, BRL1_IDLE ); done = 1; continue; } if( c == BRL1_ESC_CH ) { /* prepare to unescape the next character */ STATE_SET( sc, BRL1_ESC ); continue; } if( c == BRL1_FLAG_CH ) { /* flag signifies the end of a packet */ unsigned short crc; /* holds the crc as we calculate it */ int i; /* index variable */ brl1_sch_t *subch; /* subchannel for received packet */ brl1_notif_t callup; /* "data ready" callup */ /* whatever else may happen, we've seen a flag and we're * starting a new packet */ STATE_SET( sc, BRL1_FLAG ); SEQSTAMP_INCR(sc); /* bump the packet sequence counter */ /* if the packet body has less than 2 characters, * it can't be a well-formed packet. Discard it. */ if( cq_tent_len( q ) < /* 2 + possible length byte */ (2 + (IS_TTY_PKT(sc) ? 0 : 1)) ) { result = BRL1_PROTOCOL; cq_discard_tent( q ); STATE_SET( sc, BRL1_FLAG ); done = 1; continue; } /* check CRC */ /* accumulate CRC, starting with the header byte and * ending with the transmitted CRC. This should * result in a known good value. */ crc = crc16_calc( INIT_CRC, LAST_HDR_GET(sc) ); for( i = (q->ipos + (IS_TTY_PKT(sc) ? 0 : 2)) % BRL1_QSIZE; i != q->tent_next; i = (i + 1) % BRL1_QSIZE ) { crc = crc16_calc( crc, q->buf[i] ); } /* verify the caclulated crc against the "good" crc value; * if we fail, discard the bad packet and return an error. */ if( crc != (unsigned short)GOOD_CRC ) { result = BRL1_CRC; cq_discard_tent( q ); STATE_SET( sc, BRL1_FLAG ); done = 1; continue; } /* so the crc check was ok. Now we discard the CRC * from the end of the received bytes. */ q->tent_next += (BRL1_QSIZE - 2); q->tent_next %= BRL1_QSIZE; /* get the subchannel and lock it */ subch = &(sc->subch[SUBCH( LAST_HDR_GET(sc) )]); SUBCH_DATA_LOCK( subch ); /* if this isn't a console packet, we need to record * a length byte */ if( !IS_TTY_PKT(sc) ) { q->buf[q->ipos] = cq_tent_len( q ) - 1; } /* record packet for posterity */ cq_commit_tent( q ); result = BRL1_VALID; /* notify subchannel owner that there's something * on the queue for them */ atomic_inc(&(subch->packet_arrived)); callup = subch->rx_notify; SUBCH_DATA_UNLOCK( subch ); if( callup ) { if ( sc->uart == BRL1_LOCALUART ) unlock_console(sc->nasid); (*callup)( sc, SUBCH(LAST_HDR_GET(sc)) ); if ( sc->uart == BRL1_LOCALUART ) lock_console(sc->nasid); } continue; /* go back for more! */ } /* none of the special cases applied; we've got a normal * body character */ cq_tent_add( q, c ); break; case BRL1_ESC: /* saw an escape character. The next character will need * to be unescaped. */ q = sc->subch[ SUBCH( LAST_HDR_GET(sc) ) ].iqp; ASSERT(q); /* if the queue we want to write into is full, don't read from * the uart (this provides backpressure to the L1 side) */ if( cq_tent_full( q ) ) { result = BRL1_FULL_Q; done = 1; continue; } if( !read_uart( sc, &c, &result ) ) { /* error reading uart */ if( c != UART_NO_CHAR ) { cq_discard_tent( q ); STATE_SET( sc, BRL1_IDLE ); } done = 1; continue; } if( c == BRL1_FLAG_CH ) { /* flag after escape is an error */ STATE_SET( sc, BRL1_FLAG ); cq_discard_tent( q ); result = BRL1_PROTOCOL; done = 1; continue; } if( c == BRL1_ESC_CH ) { /* two consecutive escapes is an error */ STATE_SET( sc, BRL1_IDLE ); cq_discard_tent( q ); result = BRL1_PROTOCOL; done = 1; continue; } /* otherwise, we've got a character that needs * to be unescaped */ cq_tent_add( q, (c ^ BRL1_XOR_CH) ); STATE_SET( sc, BRL1_BODY ); break; } /* end of switch( STATE_GET(sc) ) */ } /* end of while(!done) */ if ( sc->uart == BRL1_LOCALUART ) unlock_console(sc->nasid); return result;} /* brl1_init initializes the Bedrock/L1 protocol layer. This includes * zeroing out the send and receive state information. */voidbrl1_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart ){ int i; brl1_sch_t *subch; bzero( sc, sizeof( *sc ) );#ifdef FORCE_CONSOLE_NASID nasid = (nasid_t)0;#endif sc->nasid = nasid; sc->uart = uart; sc->getc_f = (uart == BRL1_LOCALUART ? uart_getc : rtr_uart_getc); sc->putc_f = (uart == BRL1_LOCALUART ? 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); 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; /* (for now, drop elscuart packets in the kernel) */ subch->rx_notify = brl1_discard_packet; 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); 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; if( sc->uart == BRL1_LOCALUART ) { subch->iqp = kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, NASID_TO_COMPACT_NODEID(nasid) ); ASSERT( subch->iqp ); cq_init( subch->iqp ); subch->rx_notify = NULL; } else { /* we shouldn't be getting console input from remote UARTs */ subch->iqp = &sc->garbage_q; subch->rx_notify = brl1_discard_packet; } 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 = brl1_discard_packet; 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 = brl1_discard_packet; subch->iqp = &sc->garbage_q; } /* initialize synchronization structures */ spin_lock_init( &(sc->subch_lock) ); if( sc->uart == BRL1_LOCALUART ) { uart_init( sc, UART_BAUD_RATE ); } else { rtr_uart_init( sc, UART_BAUD_RATE ); } /* Set up remaining fields using L1 command functions-- elsc_module_get * to read the module id, elsc_debug_get to see whether or not we're * in verbose mode. */ { extern int elsc_module_get(l1sc_t *); sc->modid = elsc_module_get( sc ); sc->modid = (sc->modid < 0 ? INVALID_MODULE : sc->modid); sc->verbose = 1; }}/* These are functions to use from serial_in/out when in protocol * mode to send and receive uart control regs. These are external * interfaces into the protocol driver. */voidl1_control_out(int offset, int value){ nasid_t nasid = 0; //(get_elsc())->nasid; WRITE_L1_UART_REG(nasid, offset, value);
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -