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

📄 eeprom.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * * This file is subject to the terms and conditions of the GNU General Public * License.  See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 2000 Silicon Graphics, Inc. * Copyright (C) 2000 by Jack Steiner (steiner@sgi.com) *//* * WARNING:     There is more than one copy of this file in different isms. *              All copies must be kept exactly in sync. *              Do not modify this file without also updating the following: * *              irix/kern/io/eeprom.c *              stand/arcs/lib/libsk/ml/eeprom.c *		stand/arcs/lib/libkl/io/eeprom.c * *      (from time to time they might not be in sync but that's due to bringup *       activity - this comment is to remind us that they eventually have to *       get back together) * * eeprom.c * * access to board-mounted EEPROMs via the L1 system controllers * *//************************************************************************** *                                                                        * *  Copyright (C) 1999 Silicon Graphics, Inc.                             * *                                                                        * *  These coded instructions, statements, and computer programs  contain  * *  unpublished  proprietary  information of Silicon Graphics, Inc., and  * *  are protected by Federal copyright law.  They  may  not be disclosed  * *  to  third  parties  or copied or duplicated in any form, in whole or  * *  in part, without the prior written consent of Silicon Graphics, Inc.  * *                                                                        * ************************************************************************** */#include <linux/types.h>#include <linux/config.h>#include <linux/slab.h>#include <asm/sn/sgi.h>#include <asm/sn/iograph.h>#include <asm/sn/invent.h>#include <asm/sn/hcl.h>#include <asm/sn/hcl_util.h>#include <asm/sn/labelcl.h>#include <asm/sn/eeprom.h>#include <asm/sn/ksys/i2c.h>#include <asm/sn/cmn_err.h>/* #include <sys/SN/SN1/ip27log.h> */#include <asm/sn/router.h>#include <asm/sn/module.h>#include <asm/sn/ksys/l1.h>#include <asm/sn/nodepda.h>#include <asm/sn/clksupport.h>#if defined(EEPROM_DEBUG)#define db_printf(x) printk x#else#define db_printf(x) printk x#endif#define BCOPY(x,y,z)	memcpy(y,x,z)#define UNDERSCORE	0	/* don't convert underscores to hyphens */#define HYPHEN		1	/* convert underscores to hyphens */void		copy_ascii_field( char *to, char *from, int length,			          int change_underscore );uint64_t	generate_unique_id( char *sn, int sn_len );uchar_t		char_to_base36( char c );int		nicify( char *dst, eeprom_brd_record_t *src );static void	int64_to_hex_string( char *out, uint64_t val );// extern int router_lock( net_vec_t, int, int );// extern int router_unlock( net_vec_t );#define ROUTER_LOCK(p) 	// router_lock(p, 10000, 3000000)#define ROUTER_UNLOCK(p) 	// router_unlock(p)#define IP27LOG_OVNIC           "OverrideNIC"/* the following function converts an EEPROM record to a close facsimile * of the string returned by reading a Dallas Semiconductor NIC (see * one of the many incarnations of nic.c for details on that driver) */int nicify( char *dst, eeprom_brd_record_t *src ){    int field_len;    uint64_t unique_id;    char *cur_dst = dst;    eeprom_board_ia_t   *board;    board   = src->board_ia;    ASSERT( board );  /* there should always be a board info area */    /* copy part number */    strcpy( cur_dst, "Part:" );    cur_dst += strlen( cur_dst );    ASSERT( (board->part_num_tl & FIELD_FORMAT_MASK)	    == FIELD_FORMAT_ASCII );    field_len = board->part_num_tl & FIELD_LENGTH_MASK;    copy_ascii_field( cur_dst, board->part_num, field_len, HYPHEN );    cur_dst += field_len;    /* copy product name */    strcpy( cur_dst, ";Name:" );    cur_dst += strlen( cur_dst );    ASSERT( (board->product_tl & FIELD_FORMAT_MASK) == FIELD_FORMAT_ASCII );    field_len = board->product_tl & FIELD_LENGTH_MASK;    copy_ascii_field( cur_dst, board->product, field_len, UNDERSCORE );    cur_dst += field_len;    /* copy serial number */    strcpy( cur_dst, ";Serial:" );    cur_dst += strlen( cur_dst );    ASSERT( (board->serial_num_tl & FIELD_FORMAT_MASK)	    == FIELD_FORMAT_ASCII );    field_len = board->serial_num_tl & FIELD_LENGTH_MASK;    copy_ascii_field( cur_dst, board->serial_num, field_len,		      HYPHEN);    cur_dst += field_len;    /* copy revision */    strcpy( cur_dst, ";Revision:");    cur_dst += strlen( cur_dst );    ASSERT( (board->board_rev_tl & FIELD_FORMAT_MASK)	    == FIELD_FORMAT_ASCII );    field_len = board->board_rev_tl & FIELD_LENGTH_MASK;    copy_ascii_field( cur_dst, board->board_rev, field_len, HYPHEN );    cur_dst += field_len;    /* EEPROMs don't have equivalents for the Group, Capability and     * Variety fields, so we pad these with 0's     */    strcpy( cur_dst, ";Group:ff;Capability:ffffffff;Variety:ff" );    cur_dst += strlen( cur_dst );    /* use the board serial number to "fake" a laser id */    strcpy( cur_dst, ";Laser:" );    cur_dst += strlen( cur_dst );    unique_id = generate_unique_id( board->serial_num,				    board->serial_num_tl & FIELD_LENGTH_MASK );    int64_to_hex_string( cur_dst, unique_id );    strcat( dst, ";" );    return 1;}/* These functions borrow heavily from chars2* in nic.c */void copy_ascii_field( char *to, char *from, int length,		       int change_underscore ){    int i;    for( i = 0; i < length; i++ ) {	/* change underscores to hyphens if requested */	if( from[i] == '_' && change_underscore == HYPHEN )	    to[i] = '-';	/* ; and ; are separators, so mustn't appear within	 * a field */	else if( from[i] == ':' || from[i] == ';' )	    to[i] = '?';	/* I'm not sure why or if ASCII character 0xff would	 * show up in an EEPROM field, but the NIC parsing	 * routines wouldn't like it if it did... so we	 * get rid of it, just in case. */	else if( (unsigned char)from[i] == (unsigned char)0xff )	    to[i] = ' ';		/* unprintable characters are replaced with . */	else if( from[i] < ' ' || from[i] >= 0x7f )	    to[i] = '.';	/* otherwise, just copy the character */	else	    to[i] = from[i];    }    if( i == 0 ) {	to[i] = ' '; /* return at least a space... */	i++;    }    to[i] = 0;	     /* terminating null */}/* Note that int64_to_hex_string currently only has a big-endian * implementation. */#ifdef _MIPSEBstatic void int64_to_hex_string( char *out, uint64_t val ){    int i;    uchar_t table[] = "0123456789abcdef";    uchar_t *byte_ptr = (uchar_t *)&val;    for( i = 0; i < sizeof(uint64_t); i++ ) {	out[i*2] = table[ ((*byte_ptr) >> 4) & 0x0f ];	out[i*2+1] = table[ (*byte_ptr) & 0x0f ];	byte_ptr++;    }    out[i*2] = '\0';}#else /* little endian */static void int64_to_hex_string( char *out, uint64_t val ){	printk("int64_to_hex_string needs a little-endian implementation.\n");}#endif /* _MIPSEB *//* Convert a standard ASCII serial number to a unique integer * id number by treating the serial number string as though * it were a base 36 number */uint64_t generate_unique_id( char *sn, int sn_len ){    int uid = 0;    int i;    #define VALID_BASE36(c)	((c >= '0' && c <='9') \			    ||   (c >= 'A' && c <='Z') \			    ||   (c >= 'a' && c <='z'))    for( i = 0; i < sn_len; i++ ) {	if( !VALID_BASE36(sn[i]) )	    continue;	uid *= 36;	uid += char_to_base36( sn[i] );    }    if( uid == 0 )	return rtc_time();    return uid;}uchar_t char_to_base36( char c ){    uchar_t val;    if( c >= '0' && c <= '9' )	val = (c - '0');    else if( c >= 'A' && c <= 'Z' )	val = (c - 'A' + 10);    else if( c >= 'a' && c <= 'z' )	val = (c - 'a' + 10);    else val = 0;    return val;}/* given a pointer to the three-byte little-endian EEPROM representation * of date-of-manufacture, this function translates to a big-endian * integer format */int eeprom_xlate_board_mfr_date( uchar_t *src ){    int rval = 0;    rval += *src; src++;    rval += ((int)(*src) << 8); src ++;    rval += ((int)(*src) << 16);    return rval;}int eeprom_str( char *nic_str, nasid_t nasid, int component ){    eeprom_brd_record_t eep;    eeprom_board_ia_t board;    eeprom_chassis_ia_t chassis;    int r;    if( (component & C_DIMM) == C_DIMM ) {	/* this function isn't applicable to DIMMs */	return EEP_PARAM;    }    else {	eep.board_ia = &board;	eep.spd = NULL;	if( !(component & SUBORD_MASK) )	    eep.chassis_ia = &chassis;  /* only main boards have a chassis					 * info area */	else	    eep.chassis_ia = NULL;    }        switch( component & BRICK_MASK ) {      case C_BRICK:	r = cbrick_eeprom_read( &eep, nasid, component );	break;      case IO_BRICK:	r = iobrick_eeprom_read( &eep, nasid, component );	break;      default:	return EEP_PARAM;  /* must be an invalid component */    }    if( r )	return r;    if( !nicify( nic_str, &eep ) )	return EEP_NICIFY;    return EEP_OK;}int vector_eeprom_str( char *nic_str, nasid_t nasid,		       int component, net_vec_t path ){    eeprom_brd_record_t eep;    eeprom_board_ia_t board;    eeprom_chassis_ia_t chassis;    int r;    eep.board_ia = &board;    if( !(component & SUBORD_MASK) )        eep.chassis_ia = &chassis;  /* only main boards have a chassis                                     * info area */    else        eep.chassis_ia = NULL;    if( !(component & VECTOR) )	return EEP_PARAM;    if( (r = vector_eeprom_read( &eep, nasid, path, component )) )	return r;    if( !nicify( nic_str, &eep ) )        return EEP_NICIFY;    return EEP_OK;}int is_iobrick( int nasid, int widget_num ){    uint32_t wid_reg;    int part_num, mfg_num;    /* Read the widget's WIDGET_ID register to get     * its part number and mfg number     */    wid_reg = *(volatile int32_t *)        (NODE_SWIN_BASE( nasid, widget_num ) + WIDGET_ID);    part_num = (wid_reg & WIDGET_PART_NUM) >> WIDGET_PART_NUM_SHFT;    mfg_num = (wid_reg & WIDGET_MFG_NUM) >> WIDGET_MFG_NUM_SHFT;    /* Is this the "xbow part" of an XBridge?  If so, this     * widget is definitely part of an I/O brick.     */    if( part_num == XXBOW_WIDGET_PART_NUM &&	mfg_num == XXBOW_WIDGET_MFGR_NUM )	return 1;    /* Is this a "bridge part" of an XBridge?  If so, once     * again, we know this widget is part of an I/O brick.     */    if( part_num == XBRIDGE_WIDGET_PART_NUM &&	mfg_num == XBRIDGE_WIDGET_MFGR_NUM )	return 1;    return 0;}int cbrick_uid_get( nasid_t nasid, uint64_t *uid ){#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL)    return EEP_L1;#else    char uid_str[32];    char msg[BRL1_QSIZE];    int subch, len;    l1sc_t sc;    l1sc_t *scp;    int local = (nasid == get_nasid());    if ( IS_RUNNING_ON_SIMULATOR() )	return EEP_L1;    /* If the promlog variable pointed to by IP27LOG_OVNIC is set,     * use that value for the cbrick UID rather than the EEPROM     * serial number.     */#ifdef LOG_GETENV    if( ip27log_getenv( nasid, IP27LOG_OVNIC, uid_str, NULL, 0 ) >= 0 )    {	/* We successfully read IP27LOG_OVNIC, so return it as the UID. */	db_printf(( "cbrick_uid_get:"		    "Overriding UID with environment variable %s\n", 		    IP27LOG_OVNIC ));	*uid = strtoull( uid_str, NULL, 0 );	return EEP_OK;    }#endif    /* If this brick is retrieving its own uid, use the local l1sc_t to     * arbitrate access to the l1; otherwise, set up a new one.     */    if( local ) {	scp = get_l1sc();    }    else {	scp = &sc;	sc_init( &sc, nasid, BRL1_LOCALUART );    }    /* fill in msg with the opcode & params */    BZERO( msg, BRL1_QSIZE );    if( (subch = sc_open( scp, L1_ADDR_LOCAL )) < 0 )	return EEP_L1;    if( (len = sc_construct_msg( scp, subch, msg, BRL1_QSIZE,				 L1_ADDR_TASK_GENERAL,				 L1_REQ_SER_NUM, 0 )) < 0 )    {	sc_close( scp, subch );	return( EEP_L1 );    }    /* send the request to the L1 */    if( sc_command( scp, subch, msg, msg, &len ) ) {	sc_close( scp, subch );	return( EEP_L1 );    }    /* free up subchannel */    sc_close(scp, subch);    /* check response */    if( sc_interpret_resp( msg, 2, L1_ARG_ASCII, uid_str ) < 0 )    {	return( EEP_L1 );    }    *uid = generate_unique_id( uid_str, strlen( uid_str ) );    return EEP_OK;#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */}int rbrick_uid_get( nasid_t nasid, net_vec_t path, uint64_t *uid ){#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL)    return EEP_L1;#else    char uid_str[32];    char msg[BRL1_QSIZE];    int subch, len;    l1sc_t sc;    if ( IS_RUNNING_ON_SIMULATOR() )	return EEP_L1;#ifdef BRINGUP#define FAIL								\    {									\	*uid = rtc_time();						\	printk( "rbrick_uid_get failed; using current time as uid\n" );	\	return EEP_OK;							\    }#endif /* BRINGUP */    ROUTER_LOCK(path);    sc_init( &sc, nasid, path );

⌨️ 快捷键说明

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