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

📄 l1.c

📁 上传linux-jx2410的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
                /* 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));    }    atomic_dec(&(subch->packet_arrived));}/* 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 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 = atomic_read(&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 );    subch_pull_msg( subch, msg, len );    SUBCH_DATA_UNLOCK( subch );    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 is_msg = 0;    brl1_sch_t *subch = &(sc->subch[ch]);    do {	SUBCH_DATA_LOCK(subch);	is_msg = atomic_read(&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, 0);	    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 );	return( SC_NMSG );    }    subch_pull_msg( subch, msg, len );    SUBCH_DATA_UNLOCK( subch );    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 LATER    if( sc->uart == BRL1_LOCALUART ) {	return( sc_recv_intr( sc, ch, resp, len, __WAIT_RECV ) );    }    else#endif	/* LATER */    {	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[ch]);    if( atomic_read(&subch->packet_arrived) )	return 1;    brl1_receive( sc );    if( atomic_read(&subch->packet_arrived) )	return 1;    return 0;}/* for now, sc_init just calls brl1_init */voidsc_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart ){    if ( !IS_RUNNING_ON_SIMULATOR() )    	brl1_init( sc, nasid, uart );}/* sc_dispatch_env_event handles events sent from the system control * network's environmental monitor tasks. */#ifdef LINUX_KERNEL_THREADSstatic voidsc_dispatch_env_event( uint code, int argc, char *args, int maxlen ){    int j, i = 0;    uint32_t ESPcode;    switch( code ) {	/* for now, all codes do the same thing: grab two arguments	 * and print a cmn_err_tag message */      default:	/* check number of arguments */	if( argc != 2 ) {	    L1_DBG_PRF(( "sc_dispatch_env_event: "			 "expected 2 arguments, got %d\n", argc ));	    return;	}		/* get ESP code (integer argument) */	if( args[i++] != L1_ARG_INT ) {	    L1_DBG_PRF(( "sc_dispatch_env_event: "			 "expected integer argument\n" ));	    return;	}	/* WARNING: highly endian */	COPY_BUFFER_TO_INT(args, i, ESPcode);	/* verify string argument */	if( args[i++] != L1_ARG_ASCII ) {	    L1_DBG_PRF(( "sc_dispatch_env_event: "			 "expected an ASCII string\n" ));	    return;	}	for( j = i; j < maxlen; j++ ) {	    if( args[j] == '\0' ) break; /* found string termination */	}	if( j == maxlen ) {	    j--;	    L1_DBG_PRF(( "sc_dispatch_env_event: "			 "message too long-- truncating\n" ));	}	/* strip out trailing cr/lf */	for( ; 	     j > 1 && ((args[j-1] == 0xd) || (args[j-1] == 0xa)); 	     j-- );	args[j] = '\0';		/* strip out leading cr/lf */	for( ;	     i < j && ((args[i] == 0xd) || (args[i] == 0xa));	     i++ );    }}#endif	/* LINUX_KERNEL_THREADS *//* sc_event waits for events to arrive from the system controller, and * prints appropriate messages to the syslog. */#ifdef LINUX_KERNEL_THREADSstatic voidsc_event( l1sc_t *sc, int ch ){    char event[BRL1_QSIZE];    int i;    int result;    int event_len;    uint32_t ev_src;    uint32_t ev_code;    int ev_argc;    while(1) {		bzero( event, BRL1_QSIZE );	/*	 * wait for an event 	 */	result = sc_recv_intr( sc, ch, event, &event_len, 1 );	if( result != SC_SUCCESS ) {	    PRINT_WARNING("Error receiving sysctl event on nasid %d\n",		     sc->nasid );	}	else {	    /*	     * an event arrived; break it down into useful pieces	     */#if defined(L1_DEBUG) && 0	    int ix;	    printf( "Event packet received:\n" );	    for (ix = 0; ix < 64; ix++) {		printf( "%x%x ", ((event[ix] >> 4) & ((uint64_t)0xf)),			(event[ix] & ((uint64_t)0xf)) );		if( (ix % 16) == 0xf ) printf( "\n" );	    }#endif /* L1_DEBUG */	    i = 0;	    /* get event source */	    COPY_BUFFER_TO_INT(event, i, ev_src);	    COPY_BUFFER_TO_INT(event, i, ev_code);	    /* get arg count */	    ev_argc = (event[i++] & 0xffUL);	    	    /* dispatch events by task */	    switch( (ev_src & L1_ADDR_TASK_MASK) >> L1_ADDR_TASK_SHFT )	    {	      case L1_ADDR_TASK_ENV: /* environmental monitor event */		sc_dispatch_env_event( ev_code, ev_argc, &(event[i]), 				       BRL1_QSIZE - i );		break;	      default: /* unhandled task type */		L1_DBG_PRF(( "Unhandled event type received from system "			     "controllers: source task %x\n",			     (ev_src & L1_ADDR_TASK_MASK) >> L1_ADDR_TASK_SHFT			   ));	    }	}	    }			}#endif	/* LINUX_KERNEL_THREADS *//* sc_listen sets up a service thread to listen for incoming events. */voidsc_listen( l1sc_t *sc ){    int result;    brl1_sch_t *subch;    char        msg[BRL1_QSIZE];    int         len;    /* length of message being sent */

⌨️ 快捷键说明

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