📄 skvpd.c
字号:
/****************************************************************************** * * Name: skvpd.c * Project: Gigabit Ethernet Adapters, VPD-Module * Version: $Revision: 2.20 $ * Date: $Date: 2008/03/26 19:55:38 $ * Purpose: Shared software to read and write VPD * ******************************************************************************//****************************************************************************** * * LICENSE: * (C)Copyright Marvell. * * 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. * /LICENSE * ******************************************************************************//* Please refer skvpd.txt for information how to include this module. */#include "h/skdrv1st.h"#include "h/sktypes.h"#include "h/skdebug.h"#include "h/skdrv2nd.h"FILE_ID("@(#) $Id: skvpd.c,v 2.20 2008/03/26 19:55:38 malthoff Exp $ (C) Marvell.")#ifndef SPI_Y2_IS_BUSY#define SPI_Y2_IS_BUSY(w) ((w) & (1L << 30))#define SPI_Y2_CMD_MASK (0x07L << 16) /* SPI EPROM command mask */#define SPI_Y2_RD (0x09L << 16) /* SPI EPROM READ command */#endif /* !SPI_Y2_IS_BUSY *//* * Static functions */#ifndef SK_KR_PROTOstatic 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_I64 start_time; SK_I64 curr_time; SK_U16 state;#ifdef XXX /* Creates too much debug output */ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL, ("VPD wait for %s\n", event ? "Write" : "Read"));#endif /* XXX */ start_time = (SK_I64)SkOsGetTime(pAC); do { curr_time = (SK_I64)SkOsGetTime(pAC); if (curr_time - 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);#ifdef XXX /* Creates too much debug output */ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL, ("state = %x, event %x\n", state, event));#endif /* XXX */ } while ((int)(state & PCI_VPD_FLAG) == event); return(0);}#if (!defined(SK_SLIM) || defined(EFI_UNDI)) /* needs to be enabled for ASF w/o EEPORM *//****************************************************************************** * * SpiWait() - waits for a SPI read completion * * Descritption: * Waits for a completion of a SPI read transfer * The SPI transfer must complete within one SK_TICKS_PER_SEC * * returns 0: success, transfer completes * error exit(9) with a error message */static int SpiWait(SK_AC *pAC, /* Adapters Context */SK_IOC IoC) /* IO Context */{ SK_I64 start_time; SK_I64 curr_time; SK_U32 stat; SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL, ("SPI wait for")); start_time = (SK_I64)SkOsGetTime(pAC); do { curr_time = (SK_I64)SkOsGetTime(pAC); SK_IN32(IoC, SPI_CTRL, &stat); if (SPI_Y2_IS_BUSY(stat) && curr_time - start_time > SK_TICKS_PER_SEC) { SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_FATAL | SK_DBGCAT_ERR, ("ERROR:SPI wait timeout\n")); return(1); } } while (SPI_Y2_IS_BUSY(stat)); return(0);}#endif /* !SK_SLIM || EFI_UNDI */#ifdef SK_DIAG/* * 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 /* SK_DIAG */#ifdef XXX/* Write the dword 'data' at address 'addr' into the VPD EEPROM, and verify that the data is written. Needed Time:. MIN MAX. -------------------------------------------------------------------. write 1.8 ms 3.6 ms. internal write cyles 0.7 ms 7.0 ms. -------------------------------------------------------------------. over all program time 2.5 ms 10.6 ms. read 1.3 ms 2.6 ms. -------------------------------------------------------------------. over all 3.8 ms 13.2 ms. Returns 0: success 1: error, I2C transfer does not terminate 2: error, data verify error */static int VpdWriteDWord(SK_AC *pAC, /* Adapters Context */SK_IOC IoC, /* IO Context */int addr, /* VPD address */SK_U32 data) /* VPD data to write */{ /* start VPD write */ /* Don't swap here, it's a data stream of bytes */ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL, ("VPD write dword at addr 0x%x, data = 0x%x\n", addr, data)); VPD_OUT32(pAC, IoC, PCI_VPD_DAT_REG, (SK_U32)data); /* But do it here */ addr |= VPD_WRITE; VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, (SK_U16)(addr | VPD_WRITE)); /* this may take up to 10,6 ms */ if (VpdWait(pAC, IoC, VPD_WRITE)) { SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, ("Write Timed Out\n")); return(1); } /* verify data */ if (VpdReadDWord(pAC, IoC, addr) != data) { SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL, ("Data Verify Error\n")); return(2); } return(0);} /* VpdWriteDWord */#endif /* XXX */#ifndef SK_SLIM/* * 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 % SZ_LONG) == 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 = VpdWait(pAC, IoC, VPD_READ); if (Rtv != 0) { return(i); } } /* Write current byte */ VPD_OUT8(pAC, IoC, PCI_VPD_DAT_REG + (i % SZ_LONG), *(SK_U8 *)buf); if (((i % SZ_LONG) == 3) || (i == (Len - 1))) { /* New Address needs to be written to VPD_ADDR reg */ AdrReg = (SK_U16) Addr; Addr += SZ_LONG; AdrReg |= VPD_WRITE; /* WRITE operation */ VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, AdrReg); /* Wait for termination */ Rtv = VpdWait(pAC, IoC, VPD_WRITE); if (Rtv != 0) { SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, ("Write Timed Out\n")); return(i - (i % SZ_LONG)); } /* Now re-read to verify */ AdrReg &= ~VPD_WRITE; /* READ operation */ VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, AdrReg); /* Wait for termination */ Rtv = VpdWait(pAC, IoC, VPD_READ); if (Rtv != 0) { SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, ("Verify Timed Out\n")); return(i - (i % SZ_LONG)); } for (j = 0; j <= (int)(i % SZ_LONG); j++, pComp++) { VPD_IN8(pAC, IoC, PCI_VPD_DAT_REG + j, &Data); if (Data != *pComp) { /* Verify Error */ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, ("WriteStream Verify Error\n")); return(i - (i % SZ_LONG) + j); } } } } return(Len);}#endif /* !SK_SLIM *//* * 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 VpdReadStream(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; SK_U16 AdrReg; int Rtv; for (i = 0; i < Len; i++, buf++) { if ((i % SZ_LONG) == 0) { /* New Address needs to be written to VPD_ADDR reg */ AdrReg = (SK_U16) Addr; Addr += SZ_LONG; AdrReg &= ~VPD_WRITE; /* READ operation */ VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, AdrReg); /* Wait for termination */ Rtv = VpdWait(pAC, IoC, VPD_READ); if (Rtv != 0) { return(i); } } VPD_IN8(pAC, IoC, PCI_VPD_DAT_REG + (i % SZ_LONG), (SK_U8 *)buf); } return(Len);}/* * Read ore writes 'len' bytes of VPD data, starting at 'addr' from * or to the I2C EEPROM. * * Returns number of bytes read / written. */static int VpdTransferBlock(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 dir) /* transfer direction may be VPD_READ or VPD_WRITE */{ int Rtv; /* Return value */ int vpd_rom_size; SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL, ("VPD %s block, addr = 0x%x, len = %d\n", dir ? "write" : "read", addr, len)); if (len == 0) { return(0); } vpd_rom_size = pAC->vpd.rom_size; if (addr > vpd_rom_size - 4) { SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL, ("Address error: 0x%x, exp. < 0x%x\n", addr, vpd_rom_size - 4)); return(0); } if (addr + len > vpd_rom_size) { len = vpd_rom_size - addr; SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, ("Warning: len was cut to %d\n", len)); } if (dir == VPD_READ) { Rtv = VpdReadStream(pAC, IoC, buf, addr, len); }#ifndef SK_SLIM else { Rtv = VpdWriteStream(pAC, IoC, buf, addr, len); }#endif /* !SK_SLIM */ return(Rtv);}#if (!defined(SK_SLIM) || defined(EFI_UNDI)) /* needs to be enabled for ASF w/o EEPROM *//****************************************************************************** * * SpiReadBlock() - Read VPD data from SPI flash * * Description: * Read 'len' bytes of VPD data, starting at 'addr' from the SPI flash. * If the device doesn't have an EEPROM. The data VPD data is stored in the * SPI flash and is read only. * * Returns: * number of read bytes */static int SpiReadBlock(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 vpd_rom_size; int i; union { SK_U32 RegVal; SK_U8 Byte[4]; } uBuf; SK_U32 SpiCtrlReg; SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL, ("VPD SPI read block, addr = 0x%x, len = %d\n", addr, len)); if (len == 0) { return(0); } vpd_rom_size = pAC->vpd.rom_size; if (addr > vpd_rom_size - 4) { SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL, ("Address error: 0x%x, exp. < 0x%x\n", addr, vpd_rom_size - 4)); return(0); } if (addr + len > vpd_rom_size) { len = vpd_rom_size - addr; SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, ("Warning: len was cut to %d\n", len)); } addr += VPD_SPI_ADDR; for (i = 0; i < len; i++, buf++) { if ((i % SZ_LONG) == 0) { /* write spi address */ SK_OUT32(IoC, SPI_ADDR, addr); /* execute spi read command */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -