⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 l1.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 5 页
字号:
		  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 ) {                /* type mismatch */		va_end( al );		DUMP_RESP;                return -1;            }            bufptr = va_arg( al, char* ); argno++;            strcpy( (char *)bufptr, (char *)&(resp[index]) );            /* include terminating null */            index += (strlen( &(resp[index]) ) + 1);            break;          default:	    if( (l1_fld_t & L1_ARG_UNKNOWN) == L1_ARG_UNKNOWN )	    {		int *arglen;				arglen = va_arg( al, int* ); argno++;		bufptr = va_arg( al, void* ); argno++;		*arglen = ((resp[index++] & ~L1_ARG_UNKNOWN) & 0xff);		BCOPY( &(resp[index]), bufptr, *arglen  );		index += (*arglen);	    }	    	    else {		/* unhandled type */		va_end( al );		DUMP_RESP;		return -1;	    }        }    }    va_end( al );      if( (l1_fldno != 0) || (argno != resp_nargs) ) {        /* wrong number of arguments */	DUMP_RESP;        return -1;    }    return 0;}/* sc_send takes as arguments a system controller struct, a * buffer which contains a Bedrock<->L1 "request" message, * the message length, and the subchannel (presumably obtained * from an earlier invocation of sc_open) over which the * message is to be sent.  The final argument ("wait") indicates * whether the send is to be performed synchronously or not. * * sc_send returns either zero or an error value.  Synchronous sends  * (wait != 0) will not return until the data has actually been sent * to the UART.  Synchronous sends generally receive privileged * treatment.  The intent is that they be used sparingly, for such * purposes as kernel printf's (the "ducons" routines).  Run-of-the-mill * console output and L1 requests should NOT use a non-zero value * for wait. */intsc_send( l1sc_t *sc, int ch, char *msg, int len, int wait ){    char type_and_subch;    int result;    if( (ch < 0) || ( ch >= BRL1_NUM_SUBCHANS) ) {        return SC_BADSUBCH;    }    /* Verify that this is an open subchannel     */    if( sc->subch[ch].use == BRL1_SUBCH_FREE )    {        return SC_NOPEN;    }           type_and_subch = (BRL1_REQUEST | ((u_char)ch));    result = brl1_send( sc, msg, len, type_and_subch, wait );    /* If we sent as much as we asked to, return "ok". */    if( result == len )	return( SC_SUCCESS );    /* Or, if we sent less, than either the UART is busy or     * we're trying to send too large a packet anyway.     */    else if( result >= 0 && result < len )	return( SC_BUSY );    /* Or, if something else went wrong (result < 0), then     * return that error value.     */    else	return( result );}/* subch_pull_msg pulls a message off the receive queue for subch * and places it the buffer pointed to by msg.  This routine should only * be called when the caller already knows a message is available on the * receive queue (and, in the kernel, only when the subchannel data lock * is held by the caller). */static voidsubch_pull_msg( brl1_sch_t *subch, char *msg, int *len ){    sc_cq_t *q;         /* receive queue */    int before_wrap,    /* packet may be split into two different       */        after_wrap;     /*   pieces to acommodate queue wraparound      */    /* pull message off the receive queue */    q = subch->iqp;    cq_rem( q, *len );   /* remove length byte and store */    cq_discard( q );     /* remove type/subch byte and discard */    if ( *len > 0 )	(*len)--;        /* don't count type/subch byte in length returned */    if( (q->opos + (*len)) > BRL1_QSIZE ) {        before_wrap = BRL1_QSIZE - q->opos;        after_wrap = (*len) - before_wrap;    }    else {        before_wrap = (*len);        after_wrap = 0;    }    BCOPY( q->buf + q->opos, msg, before_wrap  );    if( after_wrap ) {        BCOPY( q->buf, msg + before_wrap, after_wrap  );	q->opos = after_wrap;    }    else {	q->opos = ((q->opos + before_wrap) & (BRL1_QSIZE - 1));    }    atomicAddInt( &(subch->packet_arrived), -1 );}/* sc_recv_poll can be called as a blocking or non-blocking function; * it attempts to pull a message off of the subchannel specified * in the argument list (ch). * * The "block" argument, if non-zero, is interpreted as a timeout * delay (to avoid permanent waiting). */intsc_recv_poll( l1sc_t *sc, int ch, char *msg, int *len, uint64_t block ){    int pl;             /* lock cookie */    int is_msg = 0;    brl1_sch_t *subch = &(sc->subch[ch]);    rtc_time_t exp_time = rtc_time() + block;    /* sanity check-- make sure this is an open subchannel */    if( subch->use == BRL1_SUBCH_FREE )	return( SC_NOPEN );    do {        /* kick the next lower layer and see if it pulls anything in         */	brl1_receive( sc );	is_msg = subch->packet_arrived;    } while( block && !is_msg && (rtc_time() < exp_time) );    if( !is_msg ) {	/* no message and we didn't care to wait for one */	return( SC_NMSG );    }    SUBCH_DATA_LOCK( subch, pl );    subch_pull_msg( subch, msg, len );    SUBCH_DATA_UNLOCK( subch, pl );    return( SC_SUCCESS );}    /* Like sc_recv_poll, sc_recv_intr can be called in either a blocking * or non-blocking mode.  Rather than polling until an appointed timeout, * however, sc_recv_intr sleeps on a syncrhonization variable until a * signal from the lower layer tells us that a packet has arrived. * * sc_recv_intr can't be used with remote (router) L1s. */intsc_recv_intr( l1sc_t *sc, int ch, char *msg, int *len, uint64_t block ){    int pl;             /* lock cookie */    int is_msg = 0;    brl1_sch_t *subch = &(sc->subch[ch]);    do {	SUBCH_DATA_LOCK(subch, pl);	is_msg = subch->packet_arrived;	if( !is_msg && block ) {	    /* wake me when you've got something */	    subch->rx_notify = sc_data_ready;	    sv_wait( &(subch->arrive_sv), 0, &(subch->data_lock), pl );	    if( subch->use == BRL1_SUBCH_FREE ) {		/* oops-- somebody closed our subchannel while we were		 * sleeping!		 */		/* no need to unlock since the channel's closed anyhow */		return( SC_NOPEN );	    }	}    } while( !is_msg && block );    if( !is_msg ) {	/* no message and we didn't care to wait for one */	SUBCH_DATA_UNLOCK( subch, pl );	return( SC_NMSG );    }    subch_pull_msg( subch, msg, len );    SUBCH_DATA_UNLOCK( subch, pl );    return( SC_SUCCESS );}/* sc_command implements a (blocking) combination of sc_send and sc_recv. * It is intended to be the SN1 equivalent of SN0's "elsc_command", which * issued a system controller command and then waited for a response from * the system controller before returning. * * cmd points to the outgoing command; resp points to the buffer in * which the response is to be stored.  Both buffers are assumed to * be the same length; if there is any doubt as to whether the * response buffer is long enough to hold the L1's response, then * make it BRL1_QSIZE bytes-- no Bedrock<->L1 message can be any * bigger. * * Be careful using the same buffer for both cmd and resp; it could get * hairy if there were ever an L1 command reqeuest that spanned multiple * packets.  (On the other hand, that would require some additional * rewriting of the L1 command interface anyway.) */#define __RETRIES	50#define __WAIT_SEND	( sc->uart != BRL1_LOCALUART )#define __WAIT_RECV	10000000intsc_command( l1sc_t *sc, int ch, char *cmd, char *resp, int *len ){#ifndef CONFIG_SERIAL_SGI_L1_PROTOCOL    return SC_NMSG;#else    int result;    int retries;    if ( IS_RUNNING_ON_SIMULATOR() )    	return SC_NMSG;    retries = __RETRIES;    while( (result = sc_send( sc, ch, cmd, *len, __WAIT_SEND )) < 0 ) {	if( result == SC_BUSY ) {	    retries--;	    if( retries <= 0 )		return result;	    uart_delay(500);	}	else {	    return result;	}    }        /* block on sc_recv_* */#ifdef notyet    if( sc->uart == BRL1_LOCALUART ) {	return( sc_recv_intr( sc, ch, resp, len, __WAIT_RECV ) );    }    else#endif    {	return( sc_recv_poll( sc, ch, resp, len, __WAIT_RECV ) );    }#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */}/* sc_command_kern is a knuckle-dragging, no-patience version of sc_command * used in situations where the kernel has a command that shouldn't be * delayed until the send buffer clears.  sc_command should be used instead * under most circumstances. */intsc_command_kern( l1sc_t *sc, int ch, char *cmd, char *resp, int *len ){#ifndef CONFIG_SERIAL_SGI_L1_PROTOCOL    return SC_NMSG;#else    int result;    if ( IS_RUNNING_ON_SIMULATOR() )    	return SC_NMSG;    if( (result = sc_send( sc, ch, cmd, *len, 1 )) < 0 ) {	return result;    }    return( sc_recv_poll( sc, ch, resp, len, __WAIT_RECV ) );#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */}/* sc_poll checks the queue corresponding to the given * subchannel to see if there's anything available.  If * not, it kicks the brl1 layer and then checks again. * * Returns 1 if input is available on the given queue, * 0 otherwise. */intsc_poll( l1sc_t *sc, int ch ){    brl1_sch_t *subch = &(sc->subch[

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -