b349129499
They are no longer needed now that we are in the kernel. Cc: Daniel Krueger <daniel.krueger@systec-electronic.com> Cc: Ronald Sieber <Ronald.Sieber@systec-electronic.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
1247 lines
40 KiB
C
1247 lines
40 KiB
C
/****************************************************************************
|
||
|
||
(c) SYSTEC electronic GmbH, D-07973 Greiz, August-Bebel-Str. 29
|
||
www.systec-electronic.com
|
||
|
||
Project: openPOWERLINK
|
||
|
||
Description: Ethernet driver for Realtek RTL8139 chips
|
||
except the RTL8139C+, because it has a different
|
||
Tx descriptor handling.
|
||
|
||
License:
|
||
|
||
Redistribution and use in source and binary forms, with or without
|
||
modification, are permitted provided that the following conditions
|
||
are met:
|
||
|
||
1. Redistributions of source code must retain the above copyright
|
||
notice, this list of conditions and the following disclaimer.
|
||
|
||
2. Redistributions in binary form must reproduce the above copyright
|
||
notice, this list of conditions and the following disclaimer in the
|
||
documentation and/or other materials provided with the distribution.
|
||
|
||
3. Neither the name of SYSTEC electronic GmbH nor the names of its
|
||
contributors may be used to endorse or promote products derived
|
||
from this software without prior written permission. For written
|
||
permission, please contact info@systec-electronic.com.
|
||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||
COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||
POSSIBILITY OF SUCH DAMAGE.
|
||
|
||
Severability Clause:
|
||
|
||
If a provision of this License is or becomes illegal, invalid or
|
||
unenforceable in any jurisdiction, that shall not affect:
|
||
1. the validity or enforceability in that jurisdiction of any other
|
||
provision of this License; or
|
||
2. the validity or enforceability in other jurisdictions of that or
|
||
any other provision of this License.
|
||
|
||
-------------------------------------------------------------------------
|
||
|
||
$RCSfile: Edrv8139.c,v $
|
||
|
||
$Author: D.Krueger $
|
||
|
||
$Revision: 1.10 $ $Date: 2008/11/21 09:00:38 $
|
||
|
||
$State: Exp $
|
||
|
||
Build Environment:
|
||
Dev C++ and GNU-Compiler for m68k
|
||
|
||
-------------------------------------------------------------------------
|
||
|
||
Revision History:
|
||
|
||
2008/02/05 d.k.: start of implementation
|
||
|
||
****************************************************************************/
|
||
|
||
#include "global.h"
|
||
#include "EplInc.h"
|
||
#include "edrv.h"
|
||
|
||
#include <linux/module.h>
|
||
#include <linux/kernel.h>
|
||
#include <linux/pci.h>
|
||
#include <linux/interrupt.h>
|
||
#include <linux/init.h>
|
||
#include <linux/errno.h>
|
||
#include <linux/major.h>
|
||
#include <asm/io.h>
|
||
#include <asm/uaccess.h>
|
||
#include <asm/atomic.h>
|
||
#include <asm/irq.h>
|
||
#include <linux/sched.h>
|
||
#include <linux/delay.h>
|
||
|
||
/***************************************************************************/
|
||
/* */
|
||
/* */
|
||
/* G L O B A L D E F I N I T I O N S */
|
||
/* */
|
||
/* */
|
||
/***************************************************************************/
|
||
|
||
// Buffer handling:
|
||
// All buffers are created statically (i.e. at compile time resp. at
|
||
// initialisation via kmalloc() ) and not dynamically on request (i.e. via
|
||
// EdrvAllocTxMsgBuffer().
|
||
// EdrvAllocTxMsgBuffer() searches for an unused buffer which is large enough.
|
||
// EdrvInit() may allocate some buffers with sizes less than maximum frame
|
||
// size (i.e. 1514 bytes), e.g. for SoC, SoA, StatusResponse, IdentResponse,
|
||
// NMT requests / commands. The less the size of the buffer the less the
|
||
// number of the buffer.
|
||
|
||
//---------------------------------------------------------------------------
|
||
// const defines
|
||
//---------------------------------------------------------------------------
|
||
|
||
#ifndef EDRV_MAX_TX_BUFFERS
|
||
#define EDRV_MAX_TX_BUFFERS 20
|
||
#endif
|
||
|
||
#define EDRV_MAX_FRAME_SIZE 0x600
|
||
|
||
#define EDRV_RX_BUFFER_SIZE 0x8610 // 32 kB + 16 Byte + 1,5 kB (WRAP is enabled)
|
||
#define EDRV_RX_BUFFER_LENGTH (EDRV_RX_BUFFER_SIZE & 0xF800) // buffer size cut down to 2 kB alignment
|
||
|
||
#define EDRV_TX_BUFFER_SIZE (EDRV_MAX_TX_BUFFERS * EDRV_MAX_FRAME_SIZE) // n * (MTU + 14 + 4)
|
||
|
||
#define DRV_NAME "epl"
|
||
|
||
#define EDRV_REGW_INT_MASK 0x3C // interrupt mask register
|
||
#define EDRV_REGW_INT_STATUS 0x3E // interrupt status register
|
||
#define EDRV_REGW_INT_ROK 0x0001 // Receive OK interrupt
|
||
#define EDRV_REGW_INT_RER 0x0002 // Receive error interrupt
|
||
#define EDRV_REGW_INT_TOK 0x0004 // Transmit OK interrupt
|
||
#define EDRV_REGW_INT_TER 0x0008 // Transmit error interrupt
|
||
#define EDRV_REGW_INT_RXOVW 0x0010 // Rx buffer overflow interrupt
|
||
#define EDRV_REGW_INT_PUN 0x0020 // Packet underrun/ link change interrupt
|
||
#define EDRV_REGW_INT_FOVW 0x0040 // Rx FIFO overflow interrupt
|
||
#define EDRV_REGW_INT_LENCHG 0x2000 // Cable length change interrupt
|
||
#define EDRV_REGW_INT_TIMEOUT 0x4000 // Time out interrupt
|
||
#define EDRV_REGW_INT_SERR 0x8000 // System error interrupt
|
||
#define EDRV_REGW_INT_MASK_DEF (EDRV_REGW_INT_ROK \
|
||
| EDRV_REGW_INT_RER \
|
||
| EDRV_REGW_INT_TOK \
|
||
| EDRV_REGW_INT_TER \
|
||
| EDRV_REGW_INT_RXOVW \
|
||
| EDRV_REGW_INT_FOVW \
|
||
| EDRV_REGW_INT_PUN \
|
||
| EDRV_REGW_INT_TIMEOUT \
|
||
| EDRV_REGW_INT_SERR) // default interrupt mask
|
||
|
||
#define EDRV_REGB_COMMAND 0x37 // command register
|
||
#define EDRV_REGB_COMMAND_RST 0x10
|
||
#define EDRV_REGB_COMMAND_RE 0x08
|
||
#define EDRV_REGB_COMMAND_TE 0x04
|
||
#define EDRV_REGB_COMMAND_BUFE 0x01
|
||
|
||
#define EDRV_REGB_CMD9346 0x50 // 93C46 command register
|
||
#define EDRV_REGB_CMD9346_LOCK 0x00 // lock configuration registers
|
||
#define EDRV_REGB_CMD9346_UNLOCK 0xC0 // unlock configuration registers
|
||
|
||
#define EDRV_REGDW_RCR 0x44 // Rx configuration register
|
||
#define EDRV_REGDW_RCR_NO_FTH 0x0000E000 // no receive FIFO threshold
|
||
#define EDRV_REGDW_RCR_RBLEN32K 0x00001000 // 32 kB receive buffer
|
||
#define EDRV_REGDW_RCR_MXDMAUNL 0x00000700 // unlimited maximum DMA burst size
|
||
#define EDRV_REGDW_RCR_NOWRAP 0x00000080 // do not wrap frame at end of buffer
|
||
#define EDRV_REGDW_RCR_AER 0x00000020 // accept error frames (CRC, alignment, collided)
|
||
#define EDRV_REGDW_RCR_AR 0x00000010 // accept runt
|
||
#define EDRV_REGDW_RCR_AB 0x00000008 // accept broadcast frames
|
||
#define EDRV_REGDW_RCR_AM 0x00000004 // accept multicast frames
|
||
#define EDRV_REGDW_RCR_APM 0x00000002 // accept physical match frames
|
||
#define EDRV_REGDW_RCR_AAP 0x00000001 // accept all frames
|
||
#define EDRV_REGDW_RCR_DEF (EDRV_REGDW_RCR_NO_FTH \
|
||
| EDRV_REGDW_RCR_RBLEN32K \
|
||
| EDRV_REGDW_RCR_MXDMAUNL \
|
||
| EDRV_REGDW_RCR_NOWRAP \
|
||
| EDRV_REGDW_RCR_AB \
|
||
| EDRV_REGDW_RCR_AM \
|
||
| EDRV_REGDW_RCR_APM) // default value
|
||
|
||
#define EDRV_REGDW_TCR 0x40 // Tx configuration register
|
||
#define EDRV_REGDW_TCR_VER_MASK 0x7CC00000 // mask for hardware version
|
||
#define EDRV_REGDW_TCR_VER_C 0x74000000 // RTL8139C
|
||
#define EDRV_REGDW_TCR_VER_D 0x74400000 // RTL8139D
|
||
#define EDRV_REGDW_TCR_IFG96 0x03000000 // default interframe gap (960 ns)
|
||
#define EDRV_REGDW_TCR_CRC 0x00010000 // disable appending of CRC by the controller
|
||
#define EDRV_REGDW_TCR_MXDMAUNL 0x00000700 // maximum DMA burst size of 2048 b
|
||
#define EDRV_REGDW_TCR_TXRETRY 0x00000000 // 16 retries
|
||
#define EDRV_REGDW_TCR_DEF (EDRV_REGDW_TCR_IFG96 \
|
||
| EDRV_REGDW_TCR_MXDMAUNL \
|
||
| EDRV_REGDW_TCR_TXRETRY)
|
||
|
||
#define EDRV_REGW_MULINT 0x5C // multiple interrupt select register
|
||
|
||
#define EDRV_REGDW_MPC 0x4C // missed packet counter register
|
||
|
||
#define EDRV_REGDW_TSAD0 0x20 // Transmit start address of descriptor 0
|
||
#define EDRV_REGDW_TSAD1 0x24 // Transmit start address of descriptor 1
|
||
#define EDRV_REGDW_TSAD2 0x28 // Transmit start address of descriptor 2
|
||
#define EDRV_REGDW_TSAD3 0x2C // Transmit start address of descriptor 3
|
||
#define EDRV_REGDW_TSD0 0x10 // Transmit status of descriptor 0
|
||
#define EDRV_REGDW_TSD_CRS 0x80000000 // Carrier sense lost
|
||
#define EDRV_REGDW_TSD_TABT 0x40000000 // Transmit Abort
|
||
#define EDRV_REGDW_TSD_OWC 0x20000000 // Out of window collision
|
||
#define EDRV_REGDW_TSD_TXTH_DEF 0x00020000 // Transmit FIFO threshold of 64 bytes
|
||
#define EDRV_REGDW_TSD_TOK 0x00008000 // Transmit OK
|
||
#define EDRV_REGDW_TSD_TUN 0x00004000 // Transmit FIFO underrun
|
||
#define EDRV_REGDW_TSD_OWN 0x00002000 // Owner
|
||
|
||
#define EDRV_REGDW_RBSTART 0x30 // Receive buffer start address
|
||
|
||
#define EDRV_REGW_CAPR 0x38 // Current address of packet read
|
||
|
||
#define EDRV_REGDW_IDR0 0x00 // ID register 0
|
||
#define EDRV_REGDW_IDR4 0x04 // ID register 4
|
||
|
||
#define EDRV_REGDW_MAR0 0x08 // Multicast address register 0
|
||
#define EDRV_REGDW_MAR4 0x0C // Multicast address register 4
|
||
|
||
// defines for the status word in the receive buffer
|
||
#define EDRV_RXSTAT_MAR 0x8000 // Multicast address received
|
||
#define EDRV_RXSTAT_PAM 0x4000 // Physical address matched
|
||
#define EDRV_RXSTAT_BAR 0x2000 // Broadcast address received
|
||
#define EDRV_RXSTAT_ISE 0x0020 // Invalid symbol error
|
||
#define EDRV_RXSTAT_RUNT 0x0010 // Runt packet received
|
||
#define EDRV_RXSTAT_LONG 0x0008 // Long packet
|
||
#define EDRV_RXSTAT_CRC 0x0004 // CRC error
|
||
#define EDRV_RXSTAT_FAE 0x0002 // Frame alignment error
|
||
#define EDRV_RXSTAT_ROK 0x0001 // Receive OK
|
||
|
||
#define EDRV_REGDW_WRITE(dwReg, dwVal) writel(dwVal, EdrvInstance_l.m_pIoAddr + dwReg)
|
||
#define EDRV_REGW_WRITE(dwReg, wVal) writew(wVal, EdrvInstance_l.m_pIoAddr + dwReg)
|
||
#define EDRV_REGB_WRITE(dwReg, bVal) writeb(bVal, EdrvInstance_l.m_pIoAddr + dwReg)
|
||
#define EDRV_REGDW_READ(dwReg) readl(EdrvInstance_l.m_pIoAddr + dwReg)
|
||
#define EDRV_REGW_READ(dwReg) readw(EdrvInstance_l.m_pIoAddr + dwReg)
|
||
#define EDRV_REGB_READ(dwReg) readb(EdrvInstance_l.m_pIoAddr + dwReg)
|
||
|
||
// TracePoint support for realtime-debugging
|
||
#ifdef _DBG_TRACE_POINTS_
|
||
void TgtDbgSignalTracePoint(u8 bTracePointNumber_p);
|
||
void TgtDbgPostTraceValue(u32 dwTraceValue_p);
|
||
#define TGT_DBG_SIGNAL_TRACE_POINT(p) TgtDbgSignalTracePoint(p)
|
||
#define TGT_DBG_POST_TRACE_VALUE(v) TgtDbgPostTraceValue(v)
|
||
#else
|
||
#define TGT_DBG_SIGNAL_TRACE_POINT(p)
|
||
#define TGT_DBG_POST_TRACE_VALUE(v)
|
||
#endif
|
||
|
||
#define EDRV_COUNT_SEND TGT_DBG_SIGNAL_TRACE_POINT(2)
|
||
#define EDRV_COUNT_TIMEOUT TGT_DBG_SIGNAL_TRACE_POINT(3)
|
||
#define EDRV_COUNT_PCI_ERR TGT_DBG_SIGNAL_TRACE_POINT(4)
|
||
#define EDRV_COUNT_TX TGT_DBG_SIGNAL_TRACE_POINT(5)
|
||
#define EDRV_COUNT_RX TGT_DBG_SIGNAL_TRACE_POINT(6)
|
||
#define EDRV_COUNT_LATECOLLISION TGT_DBG_SIGNAL_TRACE_POINT(10)
|
||
#define EDRV_COUNT_TX_COL_RL TGT_DBG_SIGNAL_TRACE_POINT(11)
|
||
#define EDRV_COUNT_TX_FUN TGT_DBG_SIGNAL_TRACE_POINT(12)
|
||
#define EDRV_COUNT_TX_ERR TGT_DBG_SIGNAL_TRACE_POINT(13)
|
||
#define EDRV_COUNT_RX_CRC TGT_DBG_SIGNAL_TRACE_POINT(14)
|
||
#define EDRV_COUNT_RX_ERR TGT_DBG_SIGNAL_TRACE_POINT(15)
|
||
#define EDRV_COUNT_RX_FOVW TGT_DBG_SIGNAL_TRACE_POINT(16)
|
||
#define EDRV_COUNT_RX_PUN TGT_DBG_SIGNAL_TRACE_POINT(17)
|
||
#define EDRV_COUNT_RX_FAE TGT_DBG_SIGNAL_TRACE_POINT(18)
|
||
#define EDRV_COUNT_RX_OVW TGT_DBG_SIGNAL_TRACE_POINT(19)
|
||
|
||
#define EDRV_TRACE_CAPR(x) TGT_DBG_POST_TRACE_VALUE(((x) & 0xFFFF) | 0x06000000)
|
||
#define EDRV_TRACE_RX_CRC(x) TGT_DBG_POST_TRACE_VALUE(((x) & 0xFFFF) | 0x0E000000)
|
||
#define EDRV_TRACE_RX_ERR(x) TGT_DBG_POST_TRACE_VALUE(((x) & 0xFFFF) | 0x0F000000)
|
||
#define EDRV_TRACE_RX_PUN(x) TGT_DBG_POST_TRACE_VALUE(((x) & 0xFFFF) | 0x11000000)
|
||
#define EDRV_TRACE(x) TGT_DBG_POST_TRACE_VALUE(((x) & 0xFFFF0000) | 0x0000FEC0)
|
||
|
||
//---------------------------------------------------------------------------
|
||
// local types
|
||
//---------------------------------------------------------------------------
|
||
/*
|
||
typedef struct
|
||
{
|
||
BOOL m_fUsed;
|
||
unsigned int m_uiSize;
|
||
MCD_bufDescFec *m_pBufDescr;
|
||
|
||
} tEdrvTxBufferIntern;
|
||
*/
|
||
|
||
// Private structure
|
||
typedef struct {
|
||
struct pci_dev *m_pPciDev; // pointer to PCI device structure
|
||
void *m_pIoAddr; // pointer to register space of Ethernet controller
|
||
u8 *m_pbRxBuf; // pointer to Rx buffer
|
||
dma_addr_t m_pRxBufDma;
|
||
u8 *m_pbTxBuf; // pointer to Tx buffer
|
||
dma_addr_t m_pTxBufDma;
|
||
BOOL m_afTxBufUsed[EDRV_MAX_TX_BUFFERS];
|
||
unsigned int m_uiCurTxDesc;
|
||
|
||
tEdrvInitParam m_InitParam;
|
||
tEdrvTxBuffer *m_pLastTransmittedTxBuffer;
|
||
|
||
} tEdrvInstance;
|
||
|
||
//---------------------------------------------------------------------------
|
||
// local function prototypes
|
||
//---------------------------------------------------------------------------
|
||
|
||
static int EdrvInitOne(struct pci_dev *pPciDev,
|
||
const struct pci_device_id *pId);
|
||
|
||
static void EdrvRemoveOne(struct pci_dev *pPciDev);
|
||
|
||
//---------------------------------------------------------------------------
|
||
// modul globale vars
|
||
//---------------------------------------------------------------------------
|
||
// buffers and buffer descriptors and pointers
|
||
|
||
static struct pci_device_id aEdrvPciTbl[] = {
|
||
{0x10ec, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
|
||
{0,}
|
||
};
|
||
|
||
MODULE_DEVICE_TABLE(pci, aEdrvPciTbl);
|
||
|
||
static tEdrvInstance EdrvInstance_l;
|
||
|
||
static struct pci_driver EdrvDriver = {
|
||
.name = DRV_NAME,
|
||
.id_table = aEdrvPciTbl,
|
||
.probe = EdrvInitOne,
|
||
.remove = EdrvRemoveOne,
|
||
};
|
||
|
||
/***************************************************************************/
|
||
/* */
|
||
/* */
|
||
/* C L A S S <edrv> */
|
||
/* */
|
||
/* */
|
||
/***************************************************************************/
|
||
//
|
||
// Description:
|
||
//
|
||
//
|
||
/***************************************************************************/
|
||
|
||
//=========================================================================//
|
||
// //
|
||
// P R I V A T E D E F I N I T I O N S //
|
||
// //
|
||
//=========================================================================//
|
||
|
||
//---------------------------------------------------------------------------
|
||
// const defines
|
||
//---------------------------------------------------------------------------
|
||
|
||
//---------------------------------------------------------------------------
|
||
// local types
|
||
//---------------------------------------------------------------------------
|
||
|
||
//---------------------------------------------------------------------------
|
||
// local vars
|
||
//---------------------------------------------------------------------------
|
||
|
||
//---------------------------------------------------------------------------
|
||
// local function prototypes
|
||
//---------------------------------------------------------------------------
|
||
|
||
static u8 EdrvCalcHash(u8 * pbMAC_p);
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// Function: EdrvInit
|
||
//
|
||
// Description: function for init of the Ethernet controller
|
||
//
|
||
// Parameters: pEdrvInitParam_p = pointer to struct including the init-parameters
|
||
//
|
||
// Returns: Errorcode = kEplSuccessful
|
||
// = kEplNoResource
|
||
//
|
||
// State:
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
tEplKernel EdrvInit(tEdrvInitParam * pEdrvInitParam_p)
|
||
{
|
||
tEplKernel Ret;
|
||
int iResult;
|
||
|
||
Ret = kEplSuccessful;
|
||
|
||
// clear instance structure
|
||
EPL_MEMSET(&EdrvInstance_l, 0, sizeof(EdrvInstance_l));
|
||
|
||
// save the init data
|
||
EdrvInstance_l.m_InitParam = *pEdrvInitParam_p;
|
||
|
||
// register PCI driver
|
||
iResult = pci_register_driver(&EdrvDriver);
|
||
if (iResult != 0) {
|
||
printk("%s pci_register_driver failed with %d\n", __func__,
|
||
iResult);
|
||
Ret = kEplNoResource;
|
||
goto Exit;
|
||
}
|
||
|
||
if (EdrvInstance_l.m_pPciDev == NULL) {
|
||
printk("%s m_pPciDev=NULL\n", __func__);
|
||
Ret = kEplNoResource;
|
||
goto Exit;
|
||
}
|
||
// read MAC address from controller
|
||
printk("%s local MAC = ", __func__);
|
||
for (iResult = 0; iResult < 6; iResult++) {
|
||
pEdrvInitParam_p->m_abMyMacAddr[iResult] =
|
||
EDRV_REGB_READ((EDRV_REGDW_IDR0 + iResult));
|
||
printk("%02X ",
|
||
(unsigned int)pEdrvInitParam_p->m_abMyMacAddr[iResult]);
|
||
}
|
||
printk("\n");
|
||
|
||
Exit:
|
||
return Ret;
|
||
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// Function: EdrvShutdown
|
||
//
|
||
// Description: Shutdown the Ethernet controller
|
||
//
|
||
// Parameters: void
|
||
//
|
||
// Returns: Errorcode = kEplSuccessful
|
||
//
|
||
// State:
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
tEplKernel EdrvShutdown(void)
|
||
{
|
||
|
||
// unregister PCI driver
|
||
printk("%s calling pci_unregister_driver()\n", __func__);
|
||
pci_unregister_driver(&EdrvDriver);
|
||
|
||
return kEplSuccessful;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// Function: EdrvDefineRxMacAddrEntry
|
||
//
|
||
// Description: Set a multicast entry into the Ethernet controller
|
||
//
|
||
// Parameters: pbMacAddr_p = pointer to multicast entry to set
|
||
//
|
||
// Returns: Errorcode = kEplSuccessful
|
||
//
|
||
// State:
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
tEplKernel EdrvDefineRxMacAddrEntry(u8 * pbMacAddr_p)
|
||
{
|
||
tEplKernel Ret = kEplSuccessful;
|
||
u32 dwData;
|
||
u8 bHash;
|
||
|
||
bHash = EdrvCalcHash(pbMacAddr_p);
|
||
/*
|
||
dwData = ether_crc(6, pbMacAddr_p);
|
||
|
||
printk("EdrvDefineRxMacAddrEntry('%02X:%02X:%02X:%02X:%02X:%02X') hash = %u / %u ether_crc = 0x%08lX\n",
|
||
(u16) pbMacAddr_p[0], (u16) pbMacAddr_p[1], (u16) pbMacAddr_p[2],
|
||
(u16) pbMacAddr_p[3], (u16) pbMacAddr_p[4], (u16) pbMacAddr_p[5],
|
||
(u16) bHash, (u16) (dwData >> 26), dwData);
|
||
*/
|
||
if (bHash > 31) {
|
||
dwData = EDRV_REGDW_READ(EDRV_REGDW_MAR4);
|
||
dwData |= 1 << (bHash - 32);
|
||
EDRV_REGDW_WRITE(EDRV_REGDW_MAR4, dwData);
|
||
} else {
|
||
dwData = EDRV_REGDW_READ(EDRV_REGDW_MAR0);
|
||
dwData |= 1 << bHash;
|
||
EDRV_REGDW_WRITE(EDRV_REGDW_MAR0, dwData);
|
||
}
|
||
|
||
return Ret;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// Function: EdrvUndefineRxMacAddrEntry
|
||
//
|
||
// Description: Reset a multicast entry in the Ethernet controller
|
||
//
|
||
// Parameters: pbMacAddr_p = pointer to multicast entry to reset
|
||
//
|
||
// Returns: Errorcode = kEplSuccessful
|
||
//
|
||
// State:
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
tEplKernel EdrvUndefineRxMacAddrEntry(u8 * pbMacAddr_p)
|
||
{
|
||
tEplKernel Ret = kEplSuccessful;
|
||
u32 dwData;
|
||
u8 bHash;
|
||
|
||
bHash = EdrvCalcHash(pbMacAddr_p);
|
||
|
||
if (bHash > 31) {
|
||
dwData = EDRV_REGDW_READ(EDRV_REGDW_MAR4);
|
||
dwData &= ~(1 << (bHash - 32));
|
||
EDRV_REGDW_WRITE(EDRV_REGDW_MAR4, dwData);
|
||
} else {
|
||
dwData = EDRV_REGDW_READ(EDRV_REGDW_MAR0);
|
||
dwData &= ~(1 << bHash);
|
||
EDRV_REGDW_WRITE(EDRV_REGDW_MAR0, dwData);
|
||
}
|
||
|
||
return Ret;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// Function: EdrvAllocTxMsgBuffer
|
||
//
|
||
// Description: Register a Tx-Buffer
|
||
//
|
||
// Parameters: pBuffer_p = pointer to Buffer structure
|
||
//
|
||
// Returns: Errorcode = kEplSuccessful
|
||
// = kEplEdrvNoFreeBufEntry
|
||
//
|
||
// State:
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
tEplKernel EdrvAllocTxMsgBuffer(tEdrvTxBuffer * pBuffer_p)
|
||
{
|
||
tEplKernel Ret = kEplSuccessful;
|
||
u32 i;
|
||
|
||
if (pBuffer_p->m_uiMaxBufferLen > EDRV_MAX_FRAME_SIZE) {
|
||
Ret = kEplEdrvNoFreeBufEntry;
|
||
goto Exit;
|
||
}
|
||
// search a free Tx buffer with appropriate size
|
||
for (i = 0; i < EDRV_MAX_TX_BUFFERS; i++) {
|
||
if (EdrvInstance_l.m_afTxBufUsed[i] == FALSE) {
|
||
// free channel found
|
||
EdrvInstance_l.m_afTxBufUsed[i] = TRUE;
|
||
pBuffer_p->m_uiBufferNumber = i;
|
||
pBuffer_p->m_pbBuffer =
|
||
EdrvInstance_l.m_pbTxBuf +
|
||
(i * EDRV_MAX_FRAME_SIZE);
|
||
pBuffer_p->m_uiMaxBufferLen = EDRV_MAX_FRAME_SIZE;
|
||
break;
|
||
}
|
||
}
|
||
if (i >= EDRV_MAX_TX_BUFFERS) {
|
||
Ret = kEplEdrvNoFreeBufEntry;
|
||
goto Exit;
|
||
}
|
||
|
||
Exit:
|
||
return Ret;
|
||
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// Function: EdrvReleaseTxMsgBuffer
|
||
//
|
||
// Description: Register a Tx-Buffer
|
||
//
|
||
// Parameters: pBuffer_p = pointer to Buffer structure
|
||
//
|
||
// Returns: Errorcode = kEplSuccessful
|
||
//
|
||
// State:
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
tEplKernel EdrvReleaseTxMsgBuffer(tEdrvTxBuffer * pBuffer_p)
|
||
{
|
||
unsigned int uiBufferNumber;
|
||
|
||
uiBufferNumber = pBuffer_p->m_uiBufferNumber;
|
||
|
||
if (uiBufferNumber < EDRV_MAX_TX_BUFFERS) {
|
||
EdrvInstance_l.m_afTxBufUsed[uiBufferNumber] = FALSE;
|
||
}
|
||
|
||
return kEplSuccessful;
|
||
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// Function: EdrvSendTxMsg
|
||
//
|
||
// Description: immediately starts the transmission of the buffer
|
||
//
|
||
// Parameters: pBuffer_p = buffer descriptor to transmit
|
||
//
|
||
// Returns: Errorcode = kEplSuccessful
|
||
//
|
||
// State:
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
tEplKernel EdrvSendTxMsg(tEdrvTxBuffer * pBuffer_p)
|
||
{
|
||
tEplKernel Ret = kEplSuccessful;
|
||
unsigned int uiBufferNumber;
|
||
u32 dwTemp;
|
||
|
||
uiBufferNumber = pBuffer_p->m_uiBufferNumber;
|
||
|
||
if ((uiBufferNumber >= EDRV_MAX_TX_BUFFERS)
|
||
|| (EdrvInstance_l.m_afTxBufUsed[uiBufferNumber] == FALSE)) {
|
||
Ret = kEplEdrvBufNotExisting;
|
||
goto Exit;
|
||
}
|
||
|
||
if (EdrvInstance_l.m_pLastTransmittedTxBuffer != NULL) { // transmission is already active
|
||
Ret = kEplInvalidOperation;
|
||
dwTemp =
|
||
EDRV_REGDW_READ((EDRV_REGDW_TSD0 +
|
||
(EdrvInstance_l.m_uiCurTxDesc *
|
||
sizeof(u32))));
|
||
printk("%s InvOp TSD%u = 0x%08X", __func__,
|
||
EdrvInstance_l.m_uiCurTxDesc, dwTemp);
|
||
printk(" Cmd = 0x%02X\n",
|
||
(u16) EDRV_REGB_READ(EDRV_REGB_COMMAND));
|
||
goto Exit;
|
||
}
|
||
// save pointer to buffer structure for TxHandler
|
||
EdrvInstance_l.m_pLastTransmittedTxBuffer = pBuffer_p;
|
||
|
||
EDRV_COUNT_SEND;
|
||
|
||
// pad with zeros if necessary, because controller does not do it
|
||
if (pBuffer_p->m_uiTxMsgLen < MIN_ETH_SIZE) {
|
||
EPL_MEMSET(pBuffer_p->m_pbBuffer + pBuffer_p->m_uiTxMsgLen, 0,
|
||
MIN_ETH_SIZE - pBuffer_p->m_uiTxMsgLen);
|
||
pBuffer_p->m_uiTxMsgLen = MIN_ETH_SIZE;
|
||
}
|
||
// set DMA address of buffer
|
||
EDRV_REGDW_WRITE((EDRV_REGDW_TSAD0 +
|
||
(EdrvInstance_l.m_uiCurTxDesc * sizeof(u32))),
|
||
(EdrvInstance_l.m_pTxBufDma +
|
||
(uiBufferNumber * EDRV_MAX_FRAME_SIZE)));
|
||
dwTemp =
|
||
EDRV_REGDW_READ((EDRV_REGDW_TSAD0 +
|
||
(EdrvInstance_l.m_uiCurTxDesc * sizeof(u32))));
|
||
// printk("%s TSAD%u = 0x%08lX", __func__, EdrvInstance_l.m_uiCurTxDesc, dwTemp);
|
||
|
||
// start transmission
|
||
EDRV_REGDW_WRITE((EDRV_REGDW_TSD0 +
|
||
(EdrvInstance_l.m_uiCurTxDesc * sizeof(u32))),
|
||
(EDRV_REGDW_TSD_TXTH_DEF | pBuffer_p->m_uiTxMsgLen));
|
||
dwTemp =
|
||
EDRV_REGDW_READ((EDRV_REGDW_TSD0 +
|
||
(EdrvInstance_l.m_uiCurTxDesc * sizeof(u32))));
|
||
// printk(" TSD%u = 0x%08lX / 0x%08lX\n", EdrvInstance_l.m_uiCurTxDesc, dwTemp, (u32)(EDRV_REGDW_TSD_TXTH_DEF | pBuffer_p->m_uiTxMsgLen));
|
||
|
||
Exit:
|
||
return Ret;
|
||
}
|
||
|
||
#if 0
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// Function: EdrvTxMsgReady
|
||
//
|
||
// Description: starts copying the buffer to the ethernet controller's FIFO
|
||
//
|
||
// Parameters: pbBuffer_p - bufferdescriptor to transmit
|
||
//
|
||
// Returns: Errorcode - kEplSuccessful
|
||
//
|
||
// State:
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
tEplKernel EdrvTxMsgReady(tEdrvTxBuffer * pBuffer_p)
|
||
{
|
||
tEplKernel Ret = kEplSuccessful;
|
||
unsigned int uiBufferNumber;
|
||
|
||
Exit:
|
||
return Ret;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// Function: EdrvTxMsgStart
|
||
//
|
||
// Description: starts transmission of the ethernet controller's FIFO
|
||
//
|
||
// Parameters: pbBuffer_p - bufferdescriptor to transmit
|
||
//
|
||
// Returns: Errorcode - kEplSuccessful
|
||
//
|
||
// State:
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
tEplKernel EdrvTxMsgStart(tEdrvTxBuffer * pBuffer_p)
|
||
{
|
||
tEplKernel Ret = kEplSuccessful;
|
||
|
||
return Ret;
|
||
}
|
||
#endif
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// Function: EdrvReinitRx
|
||
//
|
||
// Description: reinitialize the Rx process, because of error
|
||
//
|
||
// Parameters: void
|
||
//
|
||
// Returns: void
|
||
//
|
||
// State:
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
static void EdrvReinitRx(void)
|
||
{
|
||
u8 bCmd;
|
||
|
||
// simply switch off and on the receiver
|
||
// this will reset the CAPR register
|
||
bCmd = EDRV_REGB_READ(EDRV_REGB_COMMAND);
|
||
EDRV_REGB_WRITE(EDRV_REGB_COMMAND, (bCmd & ~EDRV_REGB_COMMAND_RE));
|
||
EDRV_REGB_WRITE(EDRV_REGB_COMMAND, bCmd);
|
||
|
||
// set receive configuration register
|
||
EDRV_REGDW_WRITE(EDRV_REGDW_RCR, EDRV_REGDW_RCR_DEF);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// Function: EdrvInterruptHandler
|
||
//
|
||
// Description: interrupt handler
|
||
//
|
||
// Parameters: void
|
||
//
|
||
// Returns: void
|
||
//
|
||
// State:
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
#if 0
|
||
void EdrvInterruptHandler(void)
|
||
{
|
||
}
|
||
#endif
|
||
|
||
static int TgtEthIsr(int nIrqNum_p, void *ppDevInstData_p)
|
||
{
|
||
// EdrvInterruptHandler();
|
||
tEdrvRxBuffer RxBuffer;
|
||
tEdrvTxBuffer *pTxBuffer;
|
||
u16 wStatus;
|
||
u32 dwTxStatus;
|
||
u32 dwRxStatus;
|
||
u16 wCurRx;
|
||
u8 *pbRxBuf;
|
||
unsigned int uiLength;
|
||
int iHandled = IRQ_HANDLED;
|
||
|
||
// printk("<22>");
|
||
|
||
// read the interrupt status
|
||
wStatus = EDRV_REGW_READ(EDRV_REGW_INT_STATUS);
|
||
|
||
// acknowledge the interrupts
|
||
EDRV_REGW_WRITE(EDRV_REGW_INT_STATUS, wStatus);
|
||
|
||
if (wStatus == 0) {
|
||
iHandled = IRQ_NONE;
|
||
goto Exit;
|
||
}
|
||
// process tasks
|
||
if ((wStatus & (EDRV_REGW_INT_TER | EDRV_REGW_INT_TOK)) != 0) { // transmit interrupt
|
||
|
||
if (EdrvInstance_l.m_pbTxBuf == NULL) {
|
||
printk("%s Tx buffers currently not allocated\n",
|
||
__func__);
|
||
goto Exit;
|
||
}
|
||
// read transmit status
|
||
dwTxStatus =
|
||
EDRV_REGDW_READ((EDRV_REGDW_TSD0 +
|
||
(EdrvInstance_l.m_uiCurTxDesc *
|
||
sizeof(u32))));
|
||
if ((dwTxStatus & (EDRV_REGDW_TSD_TOK | EDRV_REGDW_TSD_TABT | EDRV_REGDW_TSD_TUN)) != 0) { // transmit finished
|
||
EdrvInstance_l.m_uiCurTxDesc =
|
||
(EdrvInstance_l.m_uiCurTxDesc + 1) & 0x03;
|
||
pTxBuffer = EdrvInstance_l.m_pLastTransmittedTxBuffer;
|
||
EdrvInstance_l.m_pLastTransmittedTxBuffer = NULL;
|
||
|
||
if ((dwTxStatus & EDRV_REGDW_TSD_TOK) != 0) {
|
||
EDRV_COUNT_TX;
|
||
} else if ((dwTxStatus & EDRV_REGDW_TSD_TUN) != 0) {
|
||
EDRV_COUNT_TX_FUN;
|
||
} else { // assume EDRV_REGDW_TSD_TABT
|
||
EDRV_COUNT_TX_COL_RL;
|
||
}
|
||
|
||
// printk("T");
|
||
if (pTxBuffer != NULL) {
|
||
// call Tx handler of Data link layer
|
||
EdrvInstance_l.m_InitParam.
|
||
m_pfnTxHandler(pTxBuffer);
|
||
}
|
||
} else {
|
||
EDRV_COUNT_TX_ERR;
|
||
}
|
||
}
|
||
|
||
if ((wStatus & (EDRV_REGW_INT_RER | EDRV_REGW_INT_FOVW | EDRV_REGW_INT_RXOVW | EDRV_REGW_INT_PUN)) != 0) { // receive error interrupt
|
||
|
||
if ((wStatus & EDRV_REGW_INT_FOVW) != 0) {
|
||
EDRV_COUNT_RX_FOVW;
|
||
} else if ((wStatus & EDRV_REGW_INT_RXOVW) != 0) {
|
||
EDRV_COUNT_RX_OVW;
|
||
} else if ((wStatus & EDRV_REGW_INT_PUN) != 0) { // Packet underrun
|
||
EDRV_TRACE_RX_PUN(wStatus);
|
||
EDRV_COUNT_RX_PUN;
|
||
} else { /*if ((wStatus & EDRV_REGW_INT_RER) != 0) */
|
||
|
||
EDRV_TRACE_RX_ERR(wStatus);
|
||
EDRV_COUNT_RX_ERR;
|
||
}
|
||
|
||
// reinitialize Rx process
|
||
EdrvReinitRx();
|
||
}
|
||
|
||
if ((wStatus & EDRV_REGW_INT_ROK) != 0) { // receive interrupt
|
||
|
||
if (EdrvInstance_l.m_pbRxBuf == NULL) {
|
||
printk("%s Rx buffers currently not allocated\n",
|
||
__func__);
|
||
goto Exit;
|
||
}
|
||
// read current offset in receive buffer
|
||
wCurRx =
|
||
(EDRV_REGW_READ(EDRV_REGW_CAPR) +
|
||
0x10) % EDRV_RX_BUFFER_LENGTH;
|
||
|
||
while ((EDRV_REGB_READ(EDRV_REGB_COMMAND) & EDRV_REGB_COMMAND_BUFE) == 0) { // frame available
|
||
|
||
// calculate pointer to current frame in receive buffer
|
||
pbRxBuf = EdrvInstance_l.m_pbRxBuf + wCurRx;
|
||
|
||
// read receive status u32
|
||
dwRxStatus = le32_to_cpu(*((u32 *) pbRxBuf));
|
||
|
||
// calculate length of received frame
|
||
uiLength = dwRxStatus >> 16;
|
||
|
||
if (uiLength == 0xFFF0) { // frame is unfinished (maybe early Rx interrupt is active)
|
||
break;
|
||
}
|
||
|
||
if ((dwRxStatus & EDRV_RXSTAT_ROK) == 0) { // error occured while receiving this frame
|
||
// ignore it
|
||
if ((dwRxStatus & EDRV_RXSTAT_FAE) != 0) {
|
||
EDRV_COUNT_RX_FAE;
|
||
} else if ((dwRxStatus & EDRV_RXSTAT_CRC) != 0) {
|
||
EDRV_TRACE_RX_CRC(dwRxStatus);
|
||
EDRV_COUNT_RX_CRC;
|
||
} else {
|
||
EDRV_TRACE_RX_ERR(dwRxStatus);
|
||
EDRV_COUNT_RX_ERR;
|
||
}
|
||
|
||
// reinitialize Rx process
|
||
EdrvReinitRx();
|
||
|
||
break;
|
||
} else { // frame is OK
|
||
RxBuffer.m_BufferInFrame =
|
||
kEdrvBufferLastInFrame;
|
||
RxBuffer.m_uiRxMsgLen = uiLength - ETH_CRC_SIZE;
|
||
RxBuffer.m_pbBuffer =
|
||
pbRxBuf + sizeof(dwRxStatus);
|
||
|
||
// printk("R");
|
||
EDRV_COUNT_RX;
|
||
|
||
// call Rx handler of Data link layer
|
||
EdrvInstance_l.m_InitParam.
|
||
m_pfnRxHandler(&RxBuffer);
|
||
}
|
||
|
||
// calulate new offset (u32 aligned)
|
||
wCurRx =
|
||
(u16) ((wCurRx + uiLength + sizeof(dwRxStatus) +
|
||
3) & ~0x3);
|
||
EDRV_TRACE_CAPR(wCurRx - 0x10);
|
||
EDRV_REGW_WRITE(EDRV_REGW_CAPR, wCurRx - 0x10);
|
||
|
||
// reread current offset in receive buffer
|
||
wCurRx =
|
||
(EDRV_REGW_READ(EDRV_REGW_CAPR) +
|
||
0x10) % EDRV_RX_BUFFER_LENGTH;
|
||
|
||
}
|
||
}
|
||
|
||
if ((wStatus & EDRV_REGW_INT_SERR) != 0) { // PCI error
|
||
EDRV_COUNT_PCI_ERR;
|
||
}
|
||
|
||
if ((wStatus & EDRV_REGW_INT_TIMEOUT) != 0) { // Timeout
|
||
EDRV_COUNT_TIMEOUT;
|
||
}
|
||
|
||
Exit:
|
||
return iHandled;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// Function: EdrvInitOne
|
||
//
|
||
// Description: initializes one PCI device
|
||
//
|
||
// Parameters: pPciDev = pointer to corresponding PCI device structure
|
||
// pId = PCI device ID
|
||
//
|
||
// Returns: (int) = error code
|
||
//
|
||
// State:
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
|
||
static int EdrvInitOne(struct pci_dev *pPciDev, const struct pci_device_id *pId)
|
||
{
|
||
int iResult = 0;
|
||
u32 dwTemp;
|
||
|
||
if (EdrvInstance_l.m_pPciDev != NULL) { // Edrv is already connected to a PCI device
|
||
printk("%s device %s discarded\n", __func__,
|
||
pci_name(pPciDev));
|
||
iResult = -ENODEV;
|
||
goto Exit;
|
||
}
|
||
|
||
if (pPciDev->revision >= 0x20) {
|
||
printk
|
||
("%s device %s is an enhanced 8139C+ version, which is not supported\n",
|
||
__func__, pci_name(pPciDev));
|
||
iResult = -ENODEV;
|
||
goto Exit;
|
||
}
|
||
|
||
EdrvInstance_l.m_pPciDev = pPciDev;
|
||
|
||
// enable device
|
||
printk("%s enable device\n", __func__);
|
||
iResult = pci_enable_device(pPciDev);
|
||
if (iResult != 0) {
|
||
goto Exit;
|
||
}
|
||
|
||
if ((pci_resource_flags(pPciDev, 1) & IORESOURCE_MEM) == 0) {
|
||
iResult = -ENODEV;
|
||
goto Exit;
|
||
}
|
||
|
||
printk("%s request regions\n", __func__);
|
||
iResult = pci_request_regions(pPciDev, DRV_NAME);
|
||
if (iResult != 0) {
|
||
goto Exit;
|
||
}
|
||
|
||
printk("%s ioremap\n", __func__);
|
||
EdrvInstance_l.m_pIoAddr =
|
||
ioremap(pci_resource_start(pPciDev, 1),
|
||
pci_resource_len(pPciDev, 1));
|
||
if (EdrvInstance_l.m_pIoAddr == NULL) { // remap of controller's register space failed
|
||
iResult = -EIO;
|
||
goto Exit;
|
||
}
|
||
// enable PCI busmaster
|
||
printk("%s enable busmaster\n", __func__);
|
||
pci_set_master(pPciDev);
|
||
|
||
// reset controller
|
||
printk("%s reset controller\n", __func__);
|
||
EDRV_REGB_WRITE(EDRV_REGB_COMMAND, EDRV_REGB_COMMAND_RST);
|
||
|
||
// wait until reset has finished
|
||
for (iResult = 500; iResult > 0; iResult--) {
|
||
if ((EDRV_REGB_READ(EDRV_REGB_COMMAND) & EDRV_REGB_COMMAND_RST)
|
||
== 0) {
|
||
break;
|
||
}
|
||
|
||
schedule_timeout(10);
|
||
}
|
||
|
||
// check hardware version, i.e. chip ID
|
||
dwTemp = EDRV_REGDW_READ(EDRV_REGDW_TCR);
|
||
if (((dwTemp & EDRV_REGDW_TCR_VER_MASK) != EDRV_REGDW_TCR_VER_C)
|
||
&& ((dwTemp & EDRV_REGDW_TCR_VER_MASK) != EDRV_REGDW_TCR_VER_D)) { // unsupported chip
|
||
printk("%s Unsupported chip! TCR = 0x%08X\n", __func__,
|
||
dwTemp);
|
||
iResult = -ENODEV;
|
||
goto Exit;
|
||
}
|
||
// disable interrupts
|
||
printk("%s disable interrupts\n", __func__);
|
||
EDRV_REGW_WRITE(EDRV_REGW_INT_MASK, 0);
|
||
// acknowledge all pending interrupts
|
||
EDRV_REGW_WRITE(EDRV_REGW_INT_STATUS,
|
||
EDRV_REGW_READ(EDRV_REGW_INT_STATUS));
|
||
|
||
// install interrupt handler
|
||
printk("%s install interrupt handler\n", __func__);
|
||
iResult =
|
||
request_irq(pPciDev->irq, TgtEthIsr, IRQF_SHARED,
|
||
DRV_NAME /*pPciDev->dev.name */ , pPciDev);
|
||
if (iResult != 0) {
|
||
goto Exit;
|
||
}
|
||
|
||
/*
|
||
// unlock configuration registers
|
||
printk("%s unlock configuration registers\n", __func__);
|
||
EDRV_REGB_WRITE(EDRV_REGB_CMD9346, EDRV_REGB_CMD9346_UNLOCK);
|
||
|
||
// check if user specified a MAC address
|
||
printk("%s check specified MAC address\n", __func__);
|
||
for (iResult = 0; iResult < 6; iResult++)
|
||
{
|
||
if (EdrvInstance_l.m_InitParam.m_abMyMacAddr[iResult] != 0)
|
||
{
|
||
printk("%s set local MAC address\n", __func__);
|
||
// write this MAC address to controller
|
||
EDRV_REGDW_WRITE(EDRV_REGDW_IDR0,
|
||
le32_to_cpu(*((u32*)&EdrvInstance_l.m_InitParam.m_abMyMacAddr[0])));
|
||
dwTemp = EDRV_REGDW_READ(EDRV_REGDW_IDR0);
|
||
|
||
EDRV_REGDW_WRITE(EDRV_REGDW_IDR4,
|
||
le32_to_cpu(*((u32*)&EdrvInstance_l.m_InitParam.m_abMyMacAddr[4])));
|
||
dwTemp = EDRV_REGDW_READ(EDRV_REGDW_IDR4);
|
||
break;
|
||
}
|
||
}
|
||
iResult = 0;
|
||
|
||
// lock configuration registers
|
||
EDRV_REGB_WRITE(EDRV_REGB_CMD9346, EDRV_REGB_CMD9346_LOCK);
|
||
*/
|
||
|
||
// allocate buffers
|
||
printk("%s allocate buffers\n", __func__);
|
||
EdrvInstance_l.m_pbTxBuf =
|
||
pci_alloc_consistent(pPciDev, EDRV_TX_BUFFER_SIZE,
|
||
&EdrvInstance_l.m_pTxBufDma);
|
||
if (EdrvInstance_l.m_pbTxBuf == NULL) {
|
||
iResult = -ENOMEM;
|
||
goto Exit;
|
||
}
|
||
|
||
EdrvInstance_l.m_pbRxBuf =
|
||
pci_alloc_consistent(pPciDev, EDRV_RX_BUFFER_SIZE,
|
||
&EdrvInstance_l.m_pRxBufDma);
|
||
if (EdrvInstance_l.m_pbRxBuf == NULL) {
|
||
iResult = -ENOMEM;
|
||
goto Exit;
|
||
}
|
||
// reset pointers for Tx buffers
|
||
printk("%s reset pointers fo Tx buffers\n", __func__);
|
||
EDRV_REGDW_WRITE(EDRV_REGDW_TSAD0, 0);
|
||
dwTemp = EDRV_REGDW_READ(EDRV_REGDW_TSAD0);
|
||
EDRV_REGDW_WRITE(EDRV_REGDW_TSAD1, 0);
|
||
dwTemp = EDRV_REGDW_READ(EDRV_REGDW_TSAD1);
|
||
EDRV_REGDW_WRITE(EDRV_REGDW_TSAD2, 0);
|
||
dwTemp = EDRV_REGDW_READ(EDRV_REGDW_TSAD2);
|
||
EDRV_REGDW_WRITE(EDRV_REGDW_TSAD3, 0);
|
||
dwTemp = EDRV_REGDW_READ(EDRV_REGDW_TSAD3);
|
||
|
||
printk(" Command = 0x%02X\n",
|
||
(u16) EDRV_REGB_READ(EDRV_REGB_COMMAND));
|
||
|
||
// set pointer for receive buffer in controller
|
||
printk("%s set pointer to Rx buffer\n", __func__);
|
||
EDRV_REGDW_WRITE(EDRV_REGDW_RBSTART, EdrvInstance_l.m_pRxBufDma);
|
||
|
||
// enable transmitter and receiver
|
||
printk("%s enable Tx and Rx", __func__);
|
||
EDRV_REGB_WRITE(EDRV_REGB_COMMAND,
|
||
(EDRV_REGB_COMMAND_RE | EDRV_REGB_COMMAND_TE));
|
||
printk(" Command = 0x%02X\n",
|
||
(u16) EDRV_REGB_READ(EDRV_REGB_COMMAND));
|
||
|
||
// clear missed packet counter to enable Rx/Tx process
|
||
EDRV_REGDW_WRITE(EDRV_REGDW_MPC, 0);
|
||
|
||
// set transmit configuration register
|
||
printk("%s set Tx conf register", __func__);
|
||
EDRV_REGDW_WRITE(EDRV_REGDW_TCR, EDRV_REGDW_TCR_DEF);
|
||
printk(" = 0x%08X\n", EDRV_REGDW_READ(EDRV_REGDW_TCR));
|
||
|
||
// set receive configuration register
|
||
printk("%s set Rx conf register", __func__);
|
||
EDRV_REGDW_WRITE(EDRV_REGDW_RCR, EDRV_REGDW_RCR_DEF);
|
||
printk(" = 0x%08X\n", EDRV_REGDW_READ(EDRV_REGDW_RCR));
|
||
|
||
// reset multicast MAC address filter
|
||
EDRV_REGDW_WRITE(EDRV_REGDW_MAR0, 0);
|
||
dwTemp = EDRV_REGDW_READ(EDRV_REGDW_MAR0);
|
||
EDRV_REGDW_WRITE(EDRV_REGDW_MAR4, 0);
|
||
dwTemp = EDRV_REGDW_READ(EDRV_REGDW_MAR4);
|
||
|
||
/*
|
||
// enable transmitter and receiver
|
||
printk("%s enable Tx and Rx", __func__);
|
||
EDRV_REGB_WRITE(EDRV_REGB_COMMAND, (EDRV_REGB_COMMAND_RE | EDRV_REGB_COMMAND_TE));
|
||
printk(" Command = 0x%02X\n", (u16) EDRV_REGB_READ(EDRV_REGB_COMMAND));
|
||
*/
|
||
// disable early interrupts
|
||
EDRV_REGW_WRITE(EDRV_REGW_MULINT, 0);
|
||
|
||
// enable interrupts
|
||
printk("%s enable interrupts\n", __func__);
|
||
EDRV_REGW_WRITE(EDRV_REGW_INT_MASK, EDRV_REGW_INT_MASK_DEF);
|
||
|
||
Exit:
|
||
printk("%s finished with %d\n", __func__, iResult);
|
||
return iResult;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// Function: EdrvRemoveOne
|
||
//
|
||
// Description: shuts down one PCI device
|
||
//
|
||
// Parameters: pPciDev = pointer to corresponding PCI device structure
|
||
//
|
||
// Returns: (void)
|
||
//
|
||
// State:
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
|
||
static void EdrvRemoveOne(struct pci_dev *pPciDev)
|
||
{
|
||
|
||
if (EdrvInstance_l.m_pPciDev != pPciDev) { // trying to remove unknown device
|
||
BUG_ON(EdrvInstance_l.m_pPciDev != pPciDev);
|
||
goto Exit;
|
||
}
|
||
// disable transmitter and receiver
|
||
EDRV_REGB_WRITE(EDRV_REGB_COMMAND, 0);
|
||
|
||
// disable interrupts
|
||
EDRV_REGW_WRITE(EDRV_REGW_INT_MASK, 0);
|
||
|
||
// remove interrupt handler
|
||
free_irq(pPciDev->irq, pPciDev);
|
||
|
||
// free buffers
|
||
if (EdrvInstance_l.m_pbTxBuf != NULL) {
|
||
pci_free_consistent(pPciDev, EDRV_TX_BUFFER_SIZE,
|
||
EdrvInstance_l.m_pbTxBuf,
|
||
EdrvInstance_l.m_pTxBufDma);
|
||
EdrvInstance_l.m_pbTxBuf = NULL;
|
||
}
|
||
|
||
if (EdrvInstance_l.m_pbRxBuf != NULL) {
|
||
pci_free_consistent(pPciDev, EDRV_RX_BUFFER_SIZE,
|
||
EdrvInstance_l.m_pbRxBuf,
|
||
EdrvInstance_l.m_pRxBufDma);
|
||
EdrvInstance_l.m_pbRxBuf = NULL;
|
||
}
|
||
// unmap controller's register space
|
||
if (EdrvInstance_l.m_pIoAddr != NULL) {
|
||
iounmap(EdrvInstance_l.m_pIoAddr);
|
||
}
|
||
// disable the PCI device
|
||
pci_disable_device(pPciDev);
|
||
|
||
// release memory regions
|
||
pci_release_regions(pPciDev);
|
||
|
||
EdrvInstance_l.m_pPciDev = NULL;
|
||
|
||
Exit:;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// Function: EdrvCalcHash
|
||
//
|
||
// Description: function calculates the entry for the hash-table from MAC
|
||
// address
|
||
//
|
||
// Parameters: pbMAC_p - pointer to MAC address
|
||
//
|
||
// Returns: hash value
|
||
//
|
||
// State:
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
#define HASH_BITS 6 // used bits in hash
|
||
#define CRC32_POLY 0x04C11DB6 //
|
||
//#define CRC32_POLY 0xEDB88320 //
|
||
// G(x) = x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1
|
||
|
||
static u8 EdrvCalcHash(u8 * pbMAC_p)
|
||
{
|
||
u32 dwByteCounter;
|
||
u32 dwBitCounter;
|
||
u32 dwData;
|
||
u32 dwCrc;
|
||
u32 dwCarry;
|
||
u8 *pbData;
|
||
u8 bHash;
|
||
|
||
pbData = pbMAC_p;
|
||
|
||
// calculate crc32 value of mac address
|
||
dwCrc = 0xFFFFFFFF;
|
||
|
||
for (dwByteCounter = 0; dwByteCounter < 6; dwByteCounter++) {
|
||
dwData = *pbData;
|
||
pbData++;
|
||
for (dwBitCounter = 0; dwBitCounter < 8;
|
||
dwBitCounter++, dwData >>= 1) {
|
||
dwCarry = (((dwCrc >> 31) ^ dwData) & 1);
|
||
dwCrc = dwCrc << 1;
|
||
if (dwCarry != 0) {
|
||
dwCrc = (dwCrc ^ CRC32_POLY) | dwCarry;
|
||
}
|
||
}
|
||
}
|
||
|
||
// printk("MyCRC = 0x%08lX\n", dwCrc);
|
||
// only upper 6 bits (HASH_BITS) are used
|
||
// which point to specific bit in the hash registers
|
||
bHash = (u8) ((dwCrc >> (32 - HASH_BITS)) & 0x3f);
|
||
|
||
return bHash;
|
||
}
|