/******************************************************************************
*
* Name: skvpd.c
* Project: GEnesis, PCI Gigabit Ethernet Adapter
* Version: $Revision: 1.37 $
* Date: $Date: 2003/01/13 10:42:45 $
* Purpose: Shared software to read and write VPD data
*
******************************************************************************/
/******************************************************************************
*
* (C)Copyright 1998-2003 SysKonnect GmbH.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* The information in this file is provided "AS IS" without warranty.
*
******************************************************************************/
/*
Please refer skvpd.txt for information how to include this module
*/
static const char SysKonnectFileId[] =
"@(#)$Id: skvpd.c,v 1.37 2003/01/13 10:42:45 rschmidt Exp $ (C) SK";
#include "h/skdrv1st.h"
#include "h/sktypes.h"
#include "h/skdebug.h"
#include "h/skdrv2nd.h"
/*
* Static functions
*/
#ifndef SK_KR_PROTO
static SK_VPD_PARA *vpd_find_para(
SK_AC *pAC,
const char *key,
SK_VPD_PARA *p);
#else /* SK_KR_PROTO */
static SK_VPD_PARA *vpd_find_para();
#endif /* SK_KR_PROTO */
/*
* waits for a completion of a VPD transfer
* The VPD transfer must complete within SK_TICKS_PER_SEC/16
*
* returns 0: success, transfer completes
* error exit(9) with a error message
*/
static int VpdWait(
SK_AC *pAC, /* Adapters context */
SK_IOC IoC, /* IO Context */
int event) /* event to wait for (VPD_READ / VPD_write) completion*/
{
SK_U64 start_time;
SK_U16 state;
SK_DBG_MSG(pAC,SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
("VPD wait for %s\n", event?"Write":"Read"));
start_time = SkOsGetTime(pAC);
do {
if (SkOsGetTime(pAC) - start_time > SK_TICKS_PER_SEC) {
/* Bug fix AF: Thu Mar 28 2002
* Do not call: VPD_STOP(pAC, IoC);
* A pending VPD read cycle can not be aborted by writing
* VPD_WRITE to the PCI_VPD_ADR_REG (VPD address register).
* Although the write threshold in the OUR-register protects
* VPD read only space from being overwritten this does not
* protect a VPD read from being `converted` into a VPD write
* operation (on the fly). As a consequence the VPD_STOP would
* delete VPD read only data. In case of any problems with the
* I2C bus we exit the loop here. The I2C read operation can
* not be aborted except by a reset (->LR).
*/
SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_FATAL | SK_DBGCAT_ERR,
("ERROR:VPD wait timeout\n"));
return(1);
}
VPD_IN16(pAC, IoC, PCI_VPD_ADR_REG, &state);
SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
("state = %x, event %x\n",state,event));
} while((int)(state & PCI_VPD_FLAG) == event);
return(0);
}
#ifdef SKDIAG
/*
* Read the dword at address 'addr' from the VPD EEPROM.
*
* Needed Time: MIN 1,3 ms MAX 2,6 ms
*
* Note: The DWord is returned in the endianess of the machine the routine
* is running on.
*
* Returns the data read.
*/
SK_U32 VpdReadDWord(
SK_AC *pAC, /* Adapters context */
SK_IOC IoC, /* IO Context */
int addr) /* VPD address */
{
SK_U32 Rtv;
/* start VPD read */
SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
("VPD read dword at 0x%x\n",addr));
addr &= ~VPD_WRITE; /* ensure the R/W bit is set to read */
VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, (SK_U16)addr);
/* ignore return code here */
(void)VpdWait(pAC, IoC, VPD_READ);
/* Don't swap here, it's a data stream of bytes */
Rtv = 0;
VPD_IN32(pAC, IoC, PCI_VPD_DAT_REG, &Rtv);
SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
("VPD read dword data = 0x%x\n",Rtv));
return(Rtv);
}
#endif /* SKDIAG */
/*
* Read one Stream of 'len' bytes of VPD data, starting at 'addr' from
* or to the I2C EEPROM.
*
* Returns number of bytes read / written.
*/
static int VpdWriteStream(
SK_AC *pAC, /* Adapters context */
SK_IOC IoC, /* IO Context */
char *buf, /* data buffer */
int Addr, /* VPD start address */
int Len) /* number of bytes to read / to write */
{
int i;
int j;
SK_U16 AdrReg;
int Rtv;
SK_U8 * pComp; /* Compare pointer */
SK_U8 Data; /* Input Data for Compare */
/* Init Compare Pointer */
pComp = (SK_U8 *) buf;
for (i = 0; i < Len; i++, buf++) {
if ((i%sizeof(SK_U32)) == 0) {
/*
* At the begin of each cycle read the Data Reg
* So it is initialized even if only a few bytes
* are written.
*/
AdrReg = (SK_U16) Addr;
AdrReg &= ~VPD_WRITE; /* READ operation */
VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, AdrReg);
/* Wait for termination */
Rtv =