blob: a9f6d67b6ceb3617353e0a4ad1aaed928abbaacc [file] [log] [blame]
/******************************************************************************
*
* Name: skgeinit.c
* Project: Gigabit Ethernet Adapters, Common Modules
* Version: $Revision: 2.99 $
* Date: $Date: 2006/04/27 07:45:23 $
* Purpose: Contains functions to initialize the adapter
*
******************************************************************************/
/******************************************************************************
*
* LICENSE:
* (C)Copyright 1998-2002 SysKonnect.
* (C)Copyright 2002-2006 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
*
******************************************************************************/
/*#define DEBUG*/
#include <config.h>
#ifdef CONFIG_SK98
#include "h/skdrv1st.h"
#include "h/skdrv2nd.h"
/* global variables ***********************************************************/
/* local variables ************************************************************/
#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
static const char SysKonnectFileId[] =
"@(#) $Id: skgeinit.c,v 2.99 2006/04/27 07:45:23 malthoff Exp $ (C) Marvell.";
#endif
struct s_QOffTab {
int RxQOff; /* Receive Queue Address Offset */
int XsQOff; /* Sync Tx Queue Address Offset */
int XaQOff; /* Async Tx Queue Address Offset */
};
static struct s_QOffTab QOffTab[] = {
{Q_R1, Q_XS1, Q_XA1}, {Q_R2, Q_XS2, Q_XA2}
};
struct s_Config {
char ScanString[8];
SK_U32 Value;
};
static struct s_Config OemConfig = {
{'O','E','M','_','C','o','n','f'},
#ifdef SK_OEM_CONFIG
OEM_CONFIG_VALUE,
#else
0,
#endif
};
#ifndef SK_SLIM
/******************************************************************************
*
* SkGePortVlan() - Enable / Disable VLAN support
*
* Description:
* Enable or disable the VLAN support of the selected port.
* The new configuration is *not* saved over any SkGeStopPort() and
* SkGeInitPort() calls.
* Currently this function is only supported on Yukon-2/EC adapters.
*
* Returns:
* nothing
*/
void SkGePortVlan(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC, /* I/O Context */
int Port, /* Port number */
SK_BOOL Enable) /* Flag */
{
SK_U32 RxCtrl;
SK_U32 TxCtrl;
if (CHIP_ID_YUKON_2(pAC)) {
if (Enable) {
RxCtrl = RX_VLAN_STRIP_ON;
TxCtrl = TX_VLAN_TAG_ON;
}
else {
RxCtrl = RX_VLAN_STRIP_OFF;
TxCtrl = TX_VLAN_TAG_OFF;
}
SK_OUT32(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), RxCtrl);
SK_OUT32(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), TxCtrl);
}
} /* SkGePortVlan */
/******************************************************************************
*
* SkGeRxRss() - Enable / Disable RSS Hash Calculation
*
* Description:
* Enable or disable the RSS hash calculation of the selected port.
* The new configuration is *not* saved over any SkGeStopPort() and
* SkGeInitPort() calls.
* Currently this function is only supported on Yukon-2/EC adapters.
*
* Returns:
* nothing
*/
void SkGeRxRss(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC, /* I/O Context */
int Port, /* Port number */
SK_BOOL Enable) /* Flag */
{
if (CHIP_ID_YUKON_2(pAC)) {
SK_OUT32(IoC, Q_ADDR(pAC->GIni.GP[Port].PRxQOff, Q_CSR),
Enable ? BMU_ENA_RX_RSS_HASH : BMU_DIS_RX_RSS_HASH);
}
} /* SkGeRxRss */
/******************************************************************************
*
* SkGeRxCsum() - Enable / Disable Receive Checksum
*
* Description:
* Enable or disable the checksum of the selected port.
* The new configuration is *not* saved over any SkGeStopPort() and
* SkGeInitPort() calls.
* Currently this function is only supported on Yukon-2/EC adapters.
*
* Returns:
* nothing
*/
void SkGeRxCsum(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC, /* I/O Context */
int Port, /* Port number */
SK_BOOL Enable) /* Flag */
{
if (CHIP_ID_YUKON_2(pAC)) {
SK_OUT32(IoC, Q_ADDR(pAC->GIni.GP[Port].PRxQOff, Q_CSR),
Enable ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
}
} /* SkGeRxCsum */
#endif /* !SK_SLIM */
/******************************************************************************
*
* SkGePollRxD() - Enable / Disable Descriptor Polling of RxD Ring
*
* Description:
* Enable or disable the descriptor polling of the receive descriptor
* ring (RxD) for port 'Port'.
* The new configuration is *not* saved over any SkGeStopPort() and
* SkGeInitPort() calls.
*
* Returns:
* nothing
*/
void SkGePollRxD(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC, /* I/O Context */
int Port, /* Port Index (MAC_1 + n) */
SK_BOOL PollRxD) /* SK_TRUE (enable pol.), SK_FALSE (disable pol.) */
{
SK_GEPORT *pPrt;
pPrt = &pAC->GIni.GP[Port];
SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), (SK_U32)((PollRxD) ?
CSR_ENA_POL : CSR_DIS_POL));
} /* SkGePollRxD */
/******************************************************************************
*
* SkGePollTxD() - Enable / Disable Descriptor Polling of TxD Rings
*
* Description:
* Enable or disable the descriptor polling of the transmit descriptor
* ring(s) (TxD) for port 'Port'.
* The new configuration is *not* saved over any SkGeStopPort() and
* SkGeInitPort() calls.
*
* Returns:
* nothing
*/
void SkGePollTxD(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC, /* I/O Context */
int Port, /* Port Index (MAC_1 + n) */
SK_BOOL PollTxD) /* SK_TRUE (enable pol.), SK_FALSE (disable pol.) */
{
SK_GEPORT *pPrt;
SK_U32 DWord;
pPrt = &pAC->GIni.GP[Port];
DWord = (SK_U32)(PollTxD ? CSR_ENA_POL : CSR_DIS_POL);
if (pPrt->PXSQSize != 0) {
SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), DWord);
}
if (pPrt->PXAQSize != 0) {
SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), DWord);
}
} /* SkGePollTxD */
#ifndef SK_SLIM
/******************************************************************************
*
* SkGeYellowLED() - Switch the yellow LED on or off.
*
* Description:
* Switch the yellow LED on or off.
*
* Note:
* This function may be called any time after SkGeInit(Level 1).
*
* Returns:
* nothing
*/
void SkGeYellowLED(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC, /* I/O Context */
int State) /* yellow LED state, 0 = OFF, 0 != ON */
{
int LedReg;
if (CHIP_ID_YUKON_2(pAC)) {
/* different mapping on Yukon-2 */
LedReg = B0_CTST + 1;
}
else {
LedReg = B0_LED;
}
if (State == 0) {
/* Switch state LED OFF */
SK_OUT8(IoC, LedReg, LED_STAT_OFF);
}
else {
/* Switch state LED ON */
SK_OUT8(IoC, LedReg, LED_STAT_ON);
}
} /* SkGeYellowLED */
#endif /* !SK_SLIM */
#if (!defined(SK_SLIM) || defined(GENESIS))
/******************************************************************************
*
* SkGeXmitLED() - Modify the Operational Mode of a transmission LED.
*
* Description:
* The Rx or Tx LED which is specified by 'Led' will be
* enabled, disabled or switched on in test mode.
*
* Note:
* 'Led' must contain the address offset of the LEDs INI register.
*
* Usage:
* SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_ENA);
*
* Returns:
* nothing
*/
void SkGeXmitLED(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC, /* I/O Context */
int Led, /* offset to the LED Init Value register */
int Mode) /* Mode may be SK_LED_DIS, SK_LED_ENA, SK_LED_TST */
{
SK_U32 LedIni;
switch (Mode) {
case SK_LED_ENA:
LedIni = SK_XMIT_DUR * (SK_U32)pAC->GIni.GIHstClkFact / 100;
SK_OUT32(IoC, Led + XMIT_LED_INI, LedIni);
SK_OUT8(IoC, Led + XMIT_LED_CTRL, LED_START);
break;
case SK_LED_TST:
SK_OUT8(IoC, Led + XMIT_LED_TST, LED_T_ON);
SK_OUT32(IoC, Led + XMIT_LED_CNT, 100);
SK_OUT8(IoC, Led + XMIT_LED_CTRL, LED_START);
break;
case SK_LED_DIS:
default:
/*
* Do NOT stop the LED Timer here. The LED might be
* in on state. But it needs to go off.
*/
SK_OUT32(IoC, Led + XMIT_LED_CNT, 0);
SK_OUT8(IoC, Led + XMIT_LED_TST, LED_T_OFF);
}
/*
* 1000BT: the Transmit LED is driven by the PHY.
* But the default LED configuration is used for
* Level One and Broadcom PHYs.
* (Broadcom: It may be that PHY_B_PEC_EN_LTR has to be set.
* In this case it has to be added here.)
*/
} /* SkGeXmitLED */
#endif /* !SK_SLIM || GENESIS */
/******************************************************************************
*
* DoCalcAddr() - Calculates the start and the end address of a queue.
*
* Description:
* This function calculates the start and the end address of a queue.
* Afterwards the 'StartVal' is incremented to the next start position.
* If the port is already initialized the calculated values
* will be checked against the configured values and an
* error will be returned, if they are not equal.
* If the port is not initialized the values will be written to
* *StartAdr and *EndAddr.
*
* Returns:
* 0: success
* 1: configuration error
*/
static int DoCalcAddr(
SK_AC *pAC, /* Adapter Context */
SK_GEPORT SK_FAR *pPrt, /* port index */
int QuSize, /* size of the queue to configure in kB */
SK_U32 SK_FAR *StartVal, /* start value for address calculation */
SK_U32 SK_FAR *QuStartAddr,/* start addr to calculate */
SK_U32 SK_FAR *QuEndAddr) /* end address to calculate */
{
SK_U32 EndVal;
SK_U32 NextStart;
int Rtv;
Rtv = 0;
if (QuSize == 0) {
EndVal = *StartVal;
NextStart = EndVal;
}
else {
EndVal = *StartVal + ((SK_U32)QuSize * 1024) - 1;
NextStart = EndVal + 1;
}
if (pPrt->PState >= SK_PRT_INIT) {
if (*StartVal != *QuStartAddr || EndVal != *QuEndAddr) {
Rtv = 1;
}
}
else {
*QuStartAddr = *StartVal;
*QuEndAddr = EndVal;
}
*StartVal = NextStart;
return(Rtv);
} /* DoCalcAddr */
/******************************************************************************
*
* SkGeRoundQueueSize() - Round the given queue size to the adpaters QZ units
*
* Description:
* This function rounds the given queue size in kBs to adapter specific
* queue size units (Genesis and Yukon: 8 kB, Yukon-2/EC: 1 kB).
*
* Returns:
* the rounded queue size in kB
*/
static int SkGeRoundQueueSize(
SK_AC *pAC, /* Adapter Context */
int QueueSizeKB) /* Queue size in kB */
{
int QueueSizeSteps;
QueueSizeSteps = (CHIP_ID_YUKON_2(pAC)) ? QZ_STEP_Y2 : QZ_STEP;
return((QueueSizeKB + QueueSizeSteps - 1) & ~(QueueSizeSteps - 1));
} /* SkGeRoundQueueSize */
/******************************************************************************
*
* SkGeInitAssignRamToQueues() - allocate default queue sizes
*
* Description:
* This function assigns the memory to the different queues and ports.
* When DualNet is set to SK_TRUE all ports get the same amount of memory.
* Otherwise the first port gets most of the memory and all the
* other ports just the required minimum.
* This function can only be called when pAC->GIni.GIRamSize and
* pAC->GIni.GIMacsFound have been initialized, usually this happens
* at init level 1
*
* Returns:
* 0 - ok
* 1 - invalid input values
* 2 - not enough memory
*/
int SkGeInitAssignRamToQueues(
SK_AC *pAC, /* Adapter Context */
int ActivePort, /* Active Port in RLMT mode */
SK_BOOL DualNet) /* Dual Net active */
{
int i;
int UsedKilobytes; /* memory already assigned */
int ActivePortKilobytes; /* memory available for active port */
int MinQueueSize; /* min. memory for queues */
int TotalRamSize; /* total memory for queues */
SK_BOOL DualPortYukon2;
SK_GEPORT *pPrt;
if (ActivePort >= pAC->GIni.GIMacsFound) {
SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
("SkGeInitAssignRamToQueues: ActivePort (%d) invalid\n",
ActivePort));
return(1);
}
DualPortYukon2 = (CHIP_ID_YUKON_2(pAC) && pAC->GIni.GIMacsFound == 2);
TotalRamSize = pAC->GIni.GIRamSize;
if (DualPortYukon2) {
TotalRamSize *= 2;
}
MinQueueSize = SK_MIN_RXQ_SIZE + SK_MIN_TXQ_SIZE;
if (MinQueueSize > pAC->GIni.GIRamSize) {
MinQueueSize = pAC->GIni.GIRamSize;
}
if ((pAC->GIni.GIMacsFound * MinQueueSize +
RAM_QUOTA_SYNC * SK_MIN_TXQ_SIZE) > TotalRamSize) {
SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
("SkGeInitAssignRamToQueues: Not enough memory (%d)\n",
TotalRamSize));
return(2);
}
if (DualNet) {
/* every port gets the same amount of memory */
ActivePortKilobytes = TotalRamSize / pAC->GIni.GIMacsFound;
for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
pPrt = &pAC->GIni.GP[i];
if (DualPortYukon2) {
ActivePortKilobytes = pAC->GIni.GIRamSize;
}
/* take away the minimum memory for active queues */
ActivePortKilobytes -= MinQueueSize;
/* receive queue gets the minimum + 80% of the rest */
pPrt->PRxQSize = SkGeRoundQueueSize(pAC,
(int)((long)ActivePortKilobytes * RAM_QUOTA_RX) / 100)
+ SK_MIN_RXQ_SIZE;
ActivePortKilobytes -= (pPrt->PRxQSize - SK_MIN_RXQ_SIZE);
/* synchronous transmit queue */
pPrt->PXSQSize = 0;
/* asynchronous transmit queue */
pPrt->PXAQSize = SkGeRoundQueueSize(pAC,
ActivePortKilobytes + SK_MIN_TXQ_SIZE);
}
}
else { /* RLMT Mode or single link adapter */
UsedKilobytes = 0;
/* set standby queue size defaults for all standby ports */
for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
if (i != ActivePort) {
pPrt = &pAC->GIni.GP[i];
if (DualPortYukon2) {
pPrt->PRxQSize = SkGeRoundQueueSize(pAC,
(int)((long)(pAC->GIni.GIRamSize - MinQueueSize) *
RAM_QUOTA_RX) / 100) + SK_MIN_RXQ_SIZE;
pPrt->PXAQSize = pAC->GIni.GIRamSize - pPrt->PRxQSize;
}
else {
pPrt->PRxQSize = SK_MIN_RXQ_SIZE;
pPrt->PXAQSize = SK_MIN_TXQ_SIZE;
}
pPrt->PXSQSize = 0;
/* Count used RAM */
UsedKilobytes += pPrt->PRxQSize + pPrt->PXAQSize;
}
}
/* what's left? */
ActivePortKilobytes = TotalRamSize - UsedKilobytes;
/* assign it to the active port */
/* first take away the minimum memory */
ActivePortKilobytes -= MinQueueSize;
pPrt = &pAC->GIni.GP[ActivePort];
/* receive queue gets 80% of the rest */
pPrt->PRxQSize = SkGeRoundQueueSize(pAC,
(int)((long)ActivePortKilobytes * RAM_QUOTA_RX) / 100);
ActivePortKilobytes -= pPrt->PRxQSize;
/* add the minimum memory for Rx queue */
pPrt->PRxQSize += MinQueueSize/2;
/* synchronous transmit queue */
pPrt->PXSQSize = 0;
/* asynchronous transmit queue gets 20% of the rest */
pPrt->PXAQSize = SkGeRoundQueueSize(pAC, ActivePortKilobytes) +
/* add the minimum memory for Tx queue */
MinQueueSize/2;
}
#ifdef DEBUG
for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
pPrt = &pAC->GIni.GP[i];
SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
("Port %d: RxQSize=%u, TxAQSize=%u, TxSQSize=%u\n",
i, pPrt->PRxQSize, pPrt->PXAQSize, pPrt->PXSQSize));
}
#endif /* DEBUG */
return(0);
} /* SkGeInitAssignRamToQueues */
/******************************************************************************
*
* SkGeCheckQSize() - Checks the Adapters Queue Size Configuration
*
* Description:
* This function verifies the Queue Size Configuration specified
* in the variables PRxQSize, PXSQSize, and PXAQSize of all
* used ports.
* This requirements must be fullfilled to have a valid configuration:
* - The size of all queues must not exceed GIRamSize.
* - The queue sizes must be specified in units of 8 kB (Genesis & Yukon).
* - The size of Rx queues of available ports must not be
* smaller than 16 kB (Genesis & Yukon) resp. 10 kB (Yukon-2).
* - The size of at least one Tx queue (synch. or asynch.)
* of available ports must not be smaller than 16 kB (Genesis & Yukon),
* resp. 10 kB (Yukon-2) when Jumbo Frames are used.
* - The RAM start and end addresses must not be changed
* for ports which are already initialized.
* Furthermore SkGeCheckQSize() defines the Start and End Addresses
* of all ports and stores them into the HWAC port structure.
*
* Returns:
* 0: Queue Size Configuration valid
* 1: Queue Size Configuration invalid
*/
static int SkGeCheckQSize(
SK_AC *pAC, /* Adapter Context */
int Port) /* port index */
{
SK_GEPORT *pPrt;
int i;
int Rtv;
int Rtv2;
SK_U32 StartAddr;
#ifndef SK_SLIM
int UsedMem; /* total memory used (max. found ports) */
#endif
Rtv = 0;
#ifndef SK_SLIM
UsedMem = 0;
for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
pPrt = &pAC->GIni.GP[i];
if (CHIP_ID_YUKON_2(pAC)) {
UsedMem = 0;
}
else if (((pPrt->PRxQSize & QZ_UNITS) != 0 ||
(pPrt->PXSQSize & QZ_UNITS) != 0 ||
(pPrt->PXAQSize & QZ_UNITS) != 0)) {
SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E012, SKERR_HWI_E012MSG);
return(1);
}
#ifndef SK_DIAG
if (i == Port && pAC->GIni.GIRamSize > SK_MIN_RXQ_SIZE &&
pPrt->PRxQSize < SK_MIN_RXQ_SIZE) {
SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E011, SKERR_HWI_E011MSG);
return(1);
}
/*
* the size of at least one Tx queue (synch. or asynch.) has to be > 0.
* if Jumbo Frames are used, this size has to be >= 16 kB.
*/
if ((i == Port && pPrt->PXSQSize == 0 && pPrt->PXAQSize == 0) ||
(pPrt->PPortUsage == SK_JUMBO_LINK &&
((pPrt->PXSQSize > 0 && pPrt->PXSQSize < SK_MIN_TXQ_SIZE) ||
(pPrt->PXAQSize > 0 && pPrt->PXAQSize < SK_MIN_TXQ_SIZE)))) {
SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E023, SKERR_HWI_E023MSG);
return(1);
}
#endif /* !SK_DIAG */
UsedMem += pPrt->PRxQSize + pPrt->PXSQSize + pPrt->PXAQSize;
if (UsedMem > pAC->GIni.GIRamSize) {
SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E012, SKERR_HWI_E012MSG);
return(1);
}
}
#endif /* !SK_SLIM */
/* Now start address calculation */
StartAddr = pAC->GIni.GIRamOffs;
for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
pPrt = &pAC->GIni.GP[i];
if (CHIP_ID_YUKON_2(pAC)) {
StartAddr = 0;
}
/* Calculate/Check values for the receive queue */
Rtv2 = DoCalcAddr(pAC, pPrt, pPrt->PRxQSize, &StartAddr,
&pPrt->PRxQRamStart, &pPrt->PRxQRamEnd);
Rtv |= Rtv2;
/* Calculate/Check values for the synchronous Tx queue */
Rtv2 = DoCalcAddr(pAC, pPrt, pPrt->PXSQSize, &StartAddr,
&pPrt->PXsQRamStart, &pPrt->PXsQRamEnd);
Rtv |= Rtv2;
/* Calculate/Check values for the asynchronous Tx queue */
Rtv2 = DoCalcAddr(pAC, pPrt, pPrt->PXAQSize, &StartAddr,
&pPrt->PXaQRamStart, &pPrt->PXaQRamEnd);
Rtv |= Rtv2;
if (Rtv) {
SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E013, SKERR_HWI_E013MSG);
return(1);
}
}
return(0);
} /* SkGeCheckQSize */
#ifdef GENESIS
/******************************************************************************
*
* SkGeInitMacArb() - Initialize the MAC Arbiter
*
* Description:
* This function initializes the MAC Arbiter.
* It must not be called if there is still an
* initialized or active port.
*
* Returns:
* nothing
*/
static void SkGeInitMacArb(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC) /* I/O Context */
{
/* release local reset */
SK_OUT16(IoC, B3_MA_TO_CTRL, MA_RST_CLR);
/* configure timeout values */
SK_OUT8(IoC, B3_MA_TOINI_RX1, SK_MAC_TO_53);
SK_OUT8(IoC, B3_MA_TOINI_RX2, SK_MAC_TO_53);
SK_OUT8(IoC, B3_MA_TOINI_TX1, SK_MAC_TO_53);
SK_OUT8(IoC, B3_MA_TOINI_TX2, SK_MAC_TO_53);
SK_OUT8(IoC, B3_MA_RCINI_RX1, 0);
SK_OUT8(IoC, B3_MA_RCINI_RX2, 0);
SK_OUT8(IoC, B3_MA_RCINI_TX1, 0);
SK_OUT8(IoC, B3_MA_RCINI_TX2, 0);
/* recovery values are needed for XMAC II Rev. B2 only */
/* Fast Output Enable Mode was intended to use with Rev. B2, but now? */
/*
* There is no start or enable button to push, therefore
* the MAC arbiter is configured and enabled now.
*/
} /* SkGeInitMacArb */
/******************************************************************************
*
* SkGeInitPktArb() - Initialize the Packet Arbiter
*
* Description:
* This function initializes the Packet Arbiter.
* It must not be called if there is still an
* initialized or active port.
*
* Returns:
* nothing
*/
static void SkGeInitPktArb(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC) /* I/O Context */
{
/* release local reset */
SK_OUT16(IoC, B3_PA_CTRL, PA_RST_CLR);
/* configure timeout values */
SK_OUT16(IoC, B3_PA_TOINI_RX1, SK_PKT_TO_MAX);
SK_OUT16(IoC, B3_PA_TOINI_RX2, SK_PKT_TO_MAX);
SK_OUT16(IoC, B3_PA_TOINI_TX1, SK_PKT_TO_MAX);
SK_OUT16(IoC, B3_PA_TOINI_TX2, SK_PKT_TO_MAX);
/*
* enable timeout timers if jumbo frames not used
* NOTE: the packet arbiter timeout interrupt is needed for
* half duplex hangup workaround
*/
if (pAC->GIni.GP[MAC_1].PPortUsage != SK_JUMBO_LINK &&
pAC->GIni.GP[MAC_2].PPortUsage != SK_JUMBO_LINK) {
if (pAC->GIni.GIMacsFound == 1) {
SK_OUT16(IoC, B3_PA_CTRL, PA_ENA_TO_TX1);
}
else {
SK_OUT16(IoC, B3_PA_CTRL, PA_ENA_TO_TX1 | PA_ENA_TO_TX2);
}
}
} /* SkGeInitPktArb */
#endif /* GENESIS */
/******************************************************************************
*
* SkGeInitMacFifo() - Initialize the MAC FIFOs
*
* Description:
* Initialize all MAC FIFOs of the specified port
*
* Returns:
* nothing
*/
static void SkGeInitMacFifo(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC, /* I/O Context */
int Port) /* Port Index (MAC_1 + n) */
{
SK_U16 Word;
/*
* For each FIFO:
* - release local reset
* - use default value for MAC FIFO size
* - setup defaults for the control register
* - enable the FIFO
*/
#ifdef GENESIS
if (pAC->GIni.GIGenesis) {
/* configure Rx MAC FIFO */
SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_RST_CLR);
SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_RX_CTRL_DEF);
SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_ENA_OP_MD);
/* configure Tx MAC FIFO */
SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_RST_CLR);
SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_TX_CTRL_DEF);
SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_ENA_OP_MD);
/* enable frame flushing if jumbo frames used */
if (pAC->GIni.GP[Port].PPortUsage == SK_JUMBO_LINK) {
SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_ENA_FLUSH);
}
}
#endif /* GENESIS */
#ifdef YUKON
if (pAC->GIni.GIYukon) {
Word = (SK_U16)GMF_RX_CTRL_DEF;
/* disable Rx GMAC FIFO Flush for YUKON-Lite Rev. A0 only */
if (pAC->GIni.GIYukonLite /* && pAC->GIni.GIChipId == CHIP_ID_YUKON */) {
Word &= ~GMF_RX_F_FL_ON;
}
/* configure Rx GMAC FIFO */
SK_OUT8(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), (SK_U8)GMF_RST_CLR);
SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), Word);
Word = RX_FF_FL_DEF_MSK;
#ifndef SK_DIAG
if (HW_FEATURE(pAC, HWF_WA_DEV_4115)) {
/*
* Flushing must be enabled (needed for ASF see dev. #4.29),
* but the flushing mask should be disabled (see dev. #4.115)
*/
Word = 0;
}
#endif /* !SK_DIAG */
/* set Rx GMAC FIFO Flush Mask (after clearing reset) */
SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_FL_MSK), Word);
/* default: 0x0a -> 56 bytes on Yukon-1 and 64 bytes on Yukon-2 */
Word = (SK_U16)RX_GMF_FL_THR_DEF;
if (CHIP_ID_YUKON_2(pAC)) {
if (pAC->GIni.GIChipId == CHIP_ID_YUKON_EC &&
pAC->GIni.GIAsfEnabled) {
/* WA for dev. #4.30 (reduce to 0x08 -> 48 bytes) */
Word -= 2;
}
}
else {
/*
* because Pause Packet Truncation in GMAC is not working
* we have to increase the Flush Threshold to 64 bytes
* in order to flush pause packets in Rx FIFO on Yukon-1
*/
Word++;
}
/* set Rx GMAC FIFO Flush Threshold (after clearing reset) */
SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_FL_THR), Word);
/* configure Tx GMAC FIFO */
SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)GMF_RST_CLR);
SK_OUT16(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U16)GMF_TX_CTRL_DEF);
if (pAC->GIni.GIChipId == CHIP_ID_YUKON_EC_U) {
/* set Rx Pause Threshold */
SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_LP_THR), (SK_U16)SK_ECU_LLPP);
SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_UP_THR), (SK_U16)SK_ECU_ULPP);
if (pAC->GIni.GP[Port].PPortUsage == SK_JUMBO_LINK) {
/* set Tx GMAC FIFO Almost Empty Threshold */
SK_OUT16(IoC, MR_ADDR(Port, TX_GMF_AE_THR),
(SK_U16)SK_ECU_AE_THR);
/* disable Store & Forward mode for TX */
SK_OUT32(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), TX_STFW_DIS);
}
#ifdef TEST_ONLY
else {
/* enable Store & Forward mode for TX */
SK_OUT32(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), TX_STFW_ENA);
}
#endif /* TEST_ONLY */
}
}
#endif /* YUKON */
} /* SkGeInitMacFifo */
#ifdef SK_LNK_SYNC_CNT
/******************************************************************************
*
* SkGeLoadLnkSyncCnt() - Load the Link Sync Counter and starts counting
*
* Description:
* This function starts the Link Sync Counter of the specified
* port and enables the generation of an Link Sync IRQ.
* The Link Sync Counter may be used to detect an active link,
* if autonegotiation is not used.
*
* Note:
* o To ensure receiving the Link Sync Event the LinkSyncCounter
* should be initialized BEFORE clearing the XMAC's reset!
* o Enable IS_LNK_SYNC_M1 and IS_LNK_SYNC_M2 after calling this
* function.
*
* Returns:
* nothing
*/
void SkGeLoadLnkSyncCnt(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC, /* I/O Context */
int Port, /* Port Index (MAC_1 + n) */
SK_U32 CntVal) /* Counter value */
{
SK_U32 OrgIMsk;
SK_U32 NewIMsk;
SK_U32 ISrc;
SK_BOOL IrqPend;
/* stop counter */
SK_OUT8(IoC, MR_ADDR(Port, LNK_SYNC_CTRL), LNK_STOP);
/*
* ASIC problem:
* Each time starting the Link Sync Counter an IRQ is generated
* by the adapter. See problem report entry from 21.07.98
*
* Workaround: Disable Link Sync IRQ and clear the unexpeced IRQ
* if no IRQ is already pending.
*/
IrqPend = SK_FALSE;
SK_IN32(IoC, B0_ISRC, &ISrc);
SK_IN32(IoC, B0_IMSK, &OrgIMsk);
if (Port == MAC_1) {
NewIMsk = OrgIMsk & ~IS_LNK_SYNC_M1;
if ((ISrc & IS_LNK_SYNC_M1) != 0) {
IrqPend = SK_TRUE;
}
}
else {
NewIMsk = OrgIMsk & ~IS_LNK_SYNC_M2;
if ((ISrc & IS_LNK_SYNC_M2) != 0) {
IrqPend = SK_TRUE;
}
}
if (!IrqPend) {
SK_OUT32(IoC, B0_IMSK, NewIMsk);
}
/* load counter */
SK_OUT32(IoC, MR_ADDR(Port, LNK_SYNC_INI), CntVal);
/* start counter */
SK_OUT8(IoC, MR_ADDR(Port, LNK_SYNC_CTRL), LNK_START);
if (!IrqPend) {
/* clear the unexpected IRQ */
SK_OUT8(IoC, MR_ADDR(Port, LNK_SYNC_CTRL), LNK_CLR_IRQ);
/* restore the interrupt mask */
SK_OUT32(IoC, B0_IMSK, OrgIMsk);
}
} /* SkGeLoadLnkSyncCnt*/
#endif /* SK_LNK_SYNC_CNT */
#if defined(SK_DIAG) || defined(SK_CFG_SYNC)
/******************************************************************************
*
* SkGeCfgSync() - Configure synchronous bandwidth for this port.
*
* Description:
* This function may be used to configure synchronous bandwidth
* to the specified port. This may be done any time after
* initializing the port. The configuration values are NOT saved
* in the HWAC port structure and will be overwritten any
* time when stopping and starting the port.
* Any values for the synchronous configuration will be ignored
* if the size of the synchronous queue is zero!
*
* The default configuration for the synchronous service is
* TXA_ENA_FSYNC. This means if the size of
* the synchronous queue is unequal zero but no specific
* synchronous bandwidth is configured, the synchronous queue
* will always have the 'unlimited' transmit priority!
*
* This mode will be restored if the synchronous bandwidth is
* deallocated ('IntTime' = 0 and 'LimCount' = 0).
*
* Returns:
* 0: success
* 1: parameter configuration error
* 2: try to configure quality of service although no
* synchronous queue is configured
*/
int SkGeCfgSync(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC, /* I/O Context */
int Port, /* Port Index (MAC_1 + n) */
SK_U32 IntTime, /* Interval Timer Value in units of 8ns */
SK_U32 LimCount, /* Number of bytes to transfer during IntTime */
int SyncMode) /* Sync Mode: TXA_ENA_ALLOC | TXA_DIS_ALLOC | 0 */
{
int Rtv;
Rtv = 0;
/* check the parameters */
if (LimCount > IntTime ||
(LimCount == 0 && IntTime != 0) ||
(LimCount != 0 && IntTime == 0)) {
SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E010, SKERR_HWI_E010MSG);
return(1);
}
if (pAC->GIni.GP[Port].PXSQSize == 0) {
SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E009, SKERR_HWI_E009MSG);
return(2);
}
/* calculate register values */
IntTime = (IntTime / 2) * pAC->GIni.GIHstClkFact / 100;
LimCount = LimCount / 8;
if (IntTime > TXA_MAX_VAL || LimCount > TXA_MAX_VAL) {
SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E010, SKERR_HWI_E010MSG);
return(1);
}
/*
* - Enable 'Force Sync' to ensure the synchronous queue
* has the priority while configuring the new values.
* - Also 'disable alloc' to ensure the settings complies
* to the SyncMode parameter.
* - Disable 'Rate Control' to configure the new values.
* - write IntTime and LimCount
* - start 'Rate Control' and disable 'Force Sync'
* if Interval Timer or Limit Counter not zero.
*/
SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL),
TXA_ENA_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC);
SK_OUT32(IoC, MR_ADDR(Port, TXA_ITI_INI), IntTime);
SK_OUT32(IoC, MR_ADDR(Port, TXA_LIM_INI), LimCount);
SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL),
(SK_U8)(SyncMode & (TXA_ENA_ALLOC | TXA_DIS_ALLOC)));
if (IntTime != 0 || LimCount != 0) {
SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL), TXA_DIS_FSYNC | TXA_START_RC);
}
return(0);
} /* SkGeCfgSync */
#endif /* SK_DIAG || SK_CFG_SYNC*/
/******************************************************************************
*
* DoInitRamQueue() - Initialize the RAM Buffer Address of a single Queue
*
* Desccription:
* If the queue is used, enable and initialize it.
* Make sure the queue is still reset, if it is not used.
*
* Returns:
* nothing
*/
void DoInitRamQueue(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC, /* I/O Context */
int QuIoOffs, /* Queue I/O Address Offset */
SK_U32 QuStartAddr, /* Queue Start Address */
SK_U32 QuEndAddr, /* Queue End Address */
int QuType) /* Queue Type (SK_RX_SRAM_Q|SK_RX_BRAM_Q|SK_TX_RAM_Q) */
{
SK_U32 RxUpThresVal;
SK_U32 RxLoThresVal;
if (QuStartAddr != QuEndAddr) {
/* calculate thresholds, assume we have a big Rx queue */
RxUpThresVal = (QuEndAddr + 1 - QuStartAddr - SK_RB_ULPP) / 8;
RxLoThresVal = (QuEndAddr + 1 - QuStartAddr - SK_RB_LLPP_B)/8;
/* build HW address format */
QuStartAddr = QuStartAddr / 8;
QuEndAddr = QuEndAddr / 8;
/* release local reset */
SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_RST_CLR);
/* configure addresses */
SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_START), QuStartAddr);
SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_END), QuEndAddr);
SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_WP), QuStartAddr);
SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_RP), QuStartAddr);
switch (QuType) {
case SK_RX_SRAM_Q:
/* configure threshold for small Rx Queue */
RxLoThresVal += (SK_RB_LLPP_B - SK_RB_LLPP_S) / 8;
/* continue with SK_RX_BRAM_Q */
case SK_RX_BRAM_Q:
/* write threshold for Rx Queue (Pause packets) */
SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_RX_UTPP), RxUpThresVal);
SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_RX_LTPP), RxLoThresVal);
/* the high priority threshold not used */
break;
case SK_TX_RAM_Q:
/*
* Do NOT use Store & Forward under normal operation due to
* performance optimization (GENESIS only).
* But if Jumbo Frames are configured (XMAC Tx FIFO is only 4 kB)
* or YUKON is used ((GMAC Tx FIFO is only 1 kB)
* we NEED Store & Forward of the RAM buffer.
*/
if (pAC->GIni.GP[MAC_1].PPortUsage == SK_JUMBO_LINK ||
pAC->GIni.GP[MAC_2].PPortUsage == SK_JUMBO_LINK ||
pAC->GIni.GIYukon) {
/* enable Store & Forward Mode for the Tx Side */
SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_ENA_STFWD);
}
break;
}
/* set queue operational */
SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_ENA_OP_MD);
}
else {
/* ensure the queue is still disabled */
SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_RST_SET);
}
} /* DoInitRamQueue */
/******************************************************************************
*
* SkGeInitRamBufs() - Initialize the RAM Buffer Queues
*
* Description:
* Initialize all RAM Buffer Queues of the specified port
*
* Returns:
* nothing
*/
static void SkGeInitRamBufs(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC, /* I/O Context */
int Port) /* Port Index (MAC_1 + n) */
{
SK_GEPORT *pPrt;
int RxQType;
pPrt = &pAC->GIni.GP[Port];
if (pPrt->PRxQSize <= SK_MIN_RXQ_SIZE) {
RxQType = SK_RX_SRAM_Q; /* small Rx Queue */
}
else {
RxQType = SK_RX_BRAM_Q; /* big Rx Queue */
}
DoInitRamQueue(pAC, IoC, pPrt->PRxQOff, pPrt->PRxQRamStart,
pPrt->PRxQRamEnd, RxQType);
DoInitRamQueue(pAC, IoC, pPrt->PXsQOff, pPrt->PXsQRamStart,
pPrt->PXsQRamEnd, SK_TX_RAM_Q);
DoInitRamQueue(pAC, IoC, pPrt->PXaQOff, pPrt->PXaQRamStart,
pPrt->PXaQRamEnd, SK_TX_RAM_Q);
} /* SkGeInitRamBufs */
/******************************************************************************
*
* SkGeInitRamIface() - Initialize the RAM Interface
*
* Description:
* This function initializes the Adapters RAM Interface.
*
* Note:
* This function is used in the diagnostics.
*
* Returns:
* nothing
*/
void SkGeInitRamIface(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC) /* I/O Context */
{
int i;
int RamBuffers;
if (CHIP_ID_YUKON_2(pAC)) {
RamBuffers = pAC->GIni.GIMacsFound;
}
else {
RamBuffers = 1;
}
for (i = 0; i < RamBuffers; i++) {
/* release local reset */
SK_OUT8(IoC, SELECT_RAM_BUFFER(i, B3_RI_CTRL), (SK_U8)RI_RST_CLR);
/* configure timeout values */
SK_OUT8(IoC, SELECT_RAM_BUFFER(i, B3_RI_WTO_R1), SK_RI_TO_53);
SK_OUT8(IoC, SELECT_RAM_BUFFER(i, B3_RI_WTO_XA1), SK_RI_TO_53);
SK_OUT8(IoC, SELECT_RAM_BUFFER(i, B3_RI_WTO_XS1), SK_RI_TO_53);
SK_OUT8(IoC, SELECT_RAM_BUFFER(i, B3_RI_RTO_R1), SK_RI_TO_53);
SK_OUT8(IoC, SELECT_RAM_BUFFER(i, B3_RI_RTO_XA1), SK_RI_TO_53);
SK_OUT8(IoC, SELECT_RAM_BUFFER(i, B3_RI_RTO_XS1), SK_RI_TO_53);
SK_OUT8(IoC, SELECT_RAM_BUFFER(i, B3_RI_WTO_R2), SK_RI_TO_53);
SK_OUT8(IoC, SELECT_RAM_BUFFER(i, B3_RI_WTO_XA2), SK_RI_TO_53);
SK_OUT8(IoC, SELECT_RAM_BUFFER(i, B3_RI_WTO_XS2), SK_RI_TO_53);
SK_OUT8(IoC, SELECT_RAM_BUFFER(i, B3_RI_RTO_R2), SK_RI_TO_53);
SK_OUT8(IoC, SELECT_RAM_BUFFER(i, B3_RI_RTO_XA2), SK_RI_TO_53);
SK_OUT8(IoC, SELECT_RAM_BUFFER(i, B3_RI_RTO_XS2), SK_RI_TO_53);
}
} /* SkGeInitRamIface */
/******************************************************************************
*
* SkGeInitBmu() - Initialize the BMU state machines
*
* Description:
* Initialize all BMU state machines of the specified port
*
* Returns:
* nothing
*/
static void SkGeInitBmu(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC, /* I/O Context */
int Port) /* Port Index (MAC_1 + n) */
{
SK_GEPORT *pPrt;
SK_U16 RxWm;
SK_U16 TxWm;
pPrt = &pAC->GIni.GP[Port];
RxWm = SK_BMU_RX_WM;
TxWm = SK_BMU_TX_WM;
if (CHIP_ID_YUKON_2(pAC)) {
if (pAC->GIni.GIPciBus == SK_PEX_BUS) {
/* for better performance set it to 128 */
RxWm = SK_BMU_RX_WM_PEX;
}
/* Rx Queue: Release all local resets and set the watermark */
SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), BMU_CLR_RESET);
SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), BMU_OPER_INIT);
SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), BMU_FIFO_OP_ON);
SK_OUT16(IoC, Q_ADDR(pPrt->PRxQOff, Q_WM), RxWm);
if (pAC->GIni.GIChipId == CHIP_ID_YUKON_EC_U &&
pAC->GIni.GIChipRev == CHIP_REV_YU_EC_U_A1) {
/* MAC Rx RAM Read is controlled by hardware */
SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_F), F_M_RX_RAM_DIS);
}
/*
* Tx Queue: Release all local resets if the queue is used !
* set watermark
*/
if (pPrt->PXSQSize != 0 && HW_SYNC_TX_SUPPORTED(pAC)) {
/* Yukon-EC doesn't have a synchronous Tx queue */
SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), BMU_CLR_RESET);
SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), BMU_OPER_INIT);
SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), BMU_FIFO_OP_ON);
SK_OUT16(IoC, Q_ADDR(pPrt->PXsQOff, Q_WM), TxWm);
}
if (pPrt->PXAQSize != 0) {
SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), BMU_CLR_RESET);
SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), BMU_OPER_INIT);
SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), BMU_FIFO_OP_ON);
SK_OUT16(IoC, Q_ADDR(pPrt->PXaQOff, Q_WM), TxWm);
if (pAC->GIni.GIChipId == CHIP_ID_YUKON_EC_U &&
pAC->GIni.GIChipRev == CHIP_REV_YU_EC_U_A0) {
/* fix for Yukon-EC Ultra: set BMU FIFO level */
SK_OUT16(IoC, Q_ADDR(pPrt->PXaQOff, Q_AL), SK_ECU_TXFF_LEV);
}
}
}
else {
if (!pAC->GIni.GIPciSlot64 && !pAC->GIni.GIPciClock66) {
/* for better performance */
RxWm /= 2;
TxWm /= 2;
}
/* Rx Queue: Release all local resets and set the watermark */
SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_CLR_RESET);
SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_F), RxWm);
/*
* Tx Queue: Release all local resets if the queue is used !
* set watermark
*/
if (pPrt->PXSQSize != 0) {
SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_CLR_RESET);
SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_F), TxWm);
}
if (pPrt->PXAQSize != 0) {
SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_CLR_RESET);
SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_F), TxWm);
}
}
/*
* Do NOT enable the descriptor poll timers here, because
* the descriptor addresses are not specified yet.
*/
} /* SkGeInitBmu */
/******************************************************************************
*
* TestStopBit() - Test the stop bit of the queue
*
* Description:
* Stopping a queue is not as simple as it seems to be.
* If descriptor polling is enabled, it may happen
* that RX/TX stop is done and SV idle is NOT set.
* In this case we have to issue another stop command.
*
* Returns:
* The queues control status register
*/
static SK_U32 TestStopBit(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC, /* I/O Context */
int QuIoOffs) /* Queue I/O Address Offset */
{
SK_U32 QuCsr; /* CSR contents */
SK_IN32(IoC, Q_ADDR(QuIoOffs, Q_CSR), &QuCsr);
if (CHIP_ID_YUKON_2(pAC)) {
if ((QuCsr & (BMU_STOP | BMU_IDLE)) == 0) {
/* Stop Descriptor overridden by start command */
SK_OUT32(IoC, Q_ADDR(QuIoOffs, Q_CSR), BMU_STOP);
SK_IN32(IoC, Q_ADDR(QuIoOffs, Q_CSR), &QuCsr);
}
}
else {
if ((QuCsr & (CSR_STOP | CSR_SV_IDLE)) == 0) {
/* Stop Descriptor overridden by start command */
SK_OUT32(IoC, Q_ADDR(QuIoOffs, Q_CSR), CSR_STOP);
SK_IN32(IoC, Q_ADDR(QuIoOffs, Q_CSR), &QuCsr);
}
}
return(QuCsr);
} /* TestStopBit */
/******************************************************************************
*
* SkGeStopPort() - Stop the Rx/Tx activity of the port 'Port'.
*
* Description:
* After calling this function the descriptor rings and Rx and Tx
* queues of this port may be reconfigured.
*
* It is possible to stop the receive and transmit path separate or
* both together.
*
* Dir = SK_STOP_TX Stops the transmit path only and resets the MAC.
* The receive queue is still active and
* the pending Rx frames may be still transferred
* into the RxD.
* SK_STOP_RX Stop the receive path. The tansmit path
* has to be stopped once before.
* SK_STOP_ALL SK_STOP_TX + SK_STOP_RX
*
* RstMode = SK_SOFT_RST Resets the MAC, the PHY is still alive.
* SK_HARD_RST Resets the MAC and the PHY.
*
* Example:
* 1) A Link Down event was signaled for a port. Therefore the activity
* of this port should be stopped and a hardware reset should be issued
* to enable the workaround of XMAC Errata #2. But the received frames
* should not be discarded.
* ...
* SkGeStopPort(pAC, IoC, Port, SK_STOP_TX, SK_HARD_RST);
* (transfer all pending Rx frames)
* SkGeStopPort(pAC, IoC, Port, SK_STOP_RX, SK_HARD_RST);
* ...
*
* 2) An event was issued which request the driver to switch
* the 'virtual active' link to an other already active port
* as soon as possible. The frames in the receive queue of this
* port may be lost. But the PHY must not be reset during this
* event.
* ...
* SkGeStopPort(pAC, IoC, Port, SK_STOP_ALL, SK_SOFT_RST);
* ...
*
* Extended Description:
* If SK_STOP_TX is set,
* o disable the MAC's receive and transmitter to prevent
* from sending incomplete frames
* o stop the port's transmit queues before terminating the
* BMUs to prevent from performing incomplete PCI cycles
* on the PCI bus
* - The network Rx and Tx activity and PCI Tx transfer is
* disabled now.
* o reset the MAC depending on the RstMode
* o Stop Interval Timer and Limit Counter of Tx Arbiter,
* also disable Force Sync bit and Enable Alloc bit.
* o perform a local reset of the port's Tx path
* - reset the PCI FIFO of the async Tx queue
* - reset the PCI FIFO of the sync Tx queue
* - reset the RAM Buffer async Tx queue
* - reset the RAM Buffer sync Tx queue
* - reset the MAC Tx FIFO
* o switch Link and Tx LED off, stop the LED counters
*
* If SK_STOP_RX is set,
* o stop the port's receive queue
* - The path data transfer activity is fully stopped now.
* o perform a local reset of the port's Rx path
* - reset the PCI FIFO of the Rx queue
* - reset the RAM Buffer receive queue
* - reset the MAC Rx FIFO
* o switch Rx LED off, stop the LED counter
*
* If all ports are stopped,
* o reset the RAM Interface.
*
* Notes:
* o This function may be called during the driver states RESET_PORT and
* SWITCH_PORT.
*/
void SkGeStopPort(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC, /* I/O Context */
int Port, /* Port to stop (MAC_1 + n) */
int Dir, /* Direction to Stop (SK_STOP_RX, SK_STOP_TX, SK_STOP_ALL) */
int RstMode)/* Reset Mode (SK_SOFT_RST, SK_HARD_RST) */
{
SK_GEPORT *pPrt;
SK_U32 RxCsr;
SK_U32 XsCsr;
SK_U32 XaCsr;
SK_U64 ToutStart;
SK_U32 CsrStart;
SK_U32 CsrStop;
SK_U32 CsrIdle;
SK_U32 CsrTest;
SK_U8 rsl; /* FIFO read shadow level */
SK_U8 rl; /* FIFO read level */
int i;
int ToutCnt;
pPrt = &pAC->GIni.GP[Port];
/* set the proper values of Q_CSR register layout depending on the chip */
if (CHIP_ID_YUKON_2(pAC)) {
CsrStart = BMU_START;
CsrStop = BMU_STOP;
CsrIdle = BMU_IDLE;
CsrTest = BMU_IDLE;
}
else {
CsrStart = CSR_START;
CsrStop = CSR_STOP;
CsrIdle = CSR_SV_IDLE;
CsrTest = CSR_SV_IDLE | CSR_STOP;
}
if ((Dir & SK_STOP_TX) != 0) {
if (!pAC->GIni.GIAsfEnabled) {
/* disable receiver and transmitter */
SkMacRxTxDisable(pAC, IoC, Port);
}
/* stop both transmit queues */
SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CsrStop);
SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CsrStop);
/*
* If the BMU is in the reset state CSR_STOP will terminate
* immediately.
*/
ToutStart = SkOsGetTime(pAC);
ToutCnt = 0;
do {
#ifdef GENESIS
if (pAC->GIni.GIGenesis) {
/* clear Tx packet arbiter timeout IRQ */
SK_OUT16(IoC, B3_PA_CTRL, (SK_U16)((Port == MAC_1) ?
PA_CLR_TO_TX1 : PA_CLR_TO_TX2));
/*
* If the transfer stucks at the XMAC the STOP command will not
* terminate if we don't flush the XMAC's transmit FIFO !
*/
SkMacFlushTxFifo(pAC, IoC, Port);
}
#endif /* GENESIS */
XaCsr = TestStopBit(pAC, IoC, pPrt->PXaQOff);
if (HW_SYNC_TX_SUPPORTED(pAC)) {
XsCsr = TestStopBit(pAC, IoC, pPrt->PXsQOff);
}
else {
XsCsr = XaCsr;
}
if (SkOsGetTime(pAC) - ToutStart > (SK_TICKS_PER_SEC / 18)) {
/*
* Timeout of 1/18 second reached.
* This needs to be checked at 1/18 sec only.
*/
ToutCnt++;
if (ToutCnt > 1) {
/*
* If BMU stop doesn't terminate, we assume that
* we have a stable state and can reset the BMU,
* the Prefetch Unit, and RAM buffer now.
*/
break; /* ===> leave do/while loop here */
}
/*
* Cache incoherency workaround: assume a start command
* has been lost while sending the frame.
*/
ToutStart = SkOsGetTime(pAC);
if ((XsCsr & CsrStop) != 0) {
SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CsrStart);
}
if ((XaCsr & CsrStop) != 0) {
SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CsrStart);
}
/*
* After the previous operations the X(s|a)Csr does no
* longer contain the proper values
*/
XaCsr = TestStopBit(pAC, IoC, pPrt->PXaQOff);
if (HW_SYNC_TX_SUPPORTED(pAC)) {
XsCsr = TestStopBit(pAC, IoC, pPrt->PXsQOff);
}
else {
XsCsr = XaCsr;
}
}
/*
* Because of the ASIC problem report entry from 21.08.1998 it is
* required to wait until CSR_STOP is reset and CSR_SV_IDLE is set.
* (valid for GENESIS only)
*/
} while (((XsCsr & CsrTest) != CsrIdle ||
(XaCsr & CsrTest) != CsrIdle));
if (pAC->GIni.GIAsfEnabled) {
pPrt->PState = (RstMode == SK_SOFT_RST) ? SK_PRT_STOP :
SK_PRT_RESET;
}
else {
/* Reset the MAC depending on the RstMode */
if (RstMode == SK_SOFT_RST) {
SkMacSoftRst(pAC, IoC, Port);
}
else {
#ifdef SK_DIAG
if (HW_FEATURE(pAC, HWF_WA_DEV_472) && Port == MAC_1 &&
pAC->GIni.GP[MAC_2].PState == SK_PRT_RUN) {
pAC->GIni.GP[MAC_1].PState = SK_PRT_RESET;
/* set GPHY Control reset */
SK_OUT8(IoC, MR_ADDR(MAC_1, GPHY_CTRL), (SK_U8)GPC_RST_SET);
}
else {
SkMacHardRst(pAC, IoC, Port);
}
#else /* !SK_DIAG */
SkMacHardRst(pAC, IoC, Port);
#endif /* !SK_DIAG */
}
}
/* disable Force Sync bit and Enable Alloc bit */
SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL),
TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC);
/* Stop Interval Timer and Limit Counter of Tx Arbiter */
SK_OUT32(IoC, MR_ADDR(Port, TXA_ITI_INI), 0L);
SK_OUT32(IoC, MR_ADDR(Port, TXA_LIM_INI), 0L);
/* Perform a local reset of the port's Tx path */
if (CHIP_ID_YUKON_2(pAC)) {
/* Reset the PCI FIFO of the async Tx queue */
SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR),
BMU_RST_SET | BMU_FIFO_RST);
/* Reset the PCI FIFO of the sync Tx queue */
SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR),
BMU_RST_SET | BMU_FIFO_RST);
/* Reset the Tx prefetch units */
SK_OUT32(IoC, Y2_PREF_Q_ADDR(pPrt->PXaQOff, PREF_UNIT_CTRL_REG),
PREF_UNIT_RST_SET);
SK_OUT32(IoC, Y2_PREF_Q_ADDR(pPrt->PXsQOff, PREF_UNIT_CTRL_REG),
PREF_UNIT_RST_SET);
}
else {
/* Reset the PCI FIFO of the async Tx queue */
SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_SET_RESET);
/* Reset the PCI FIFO of the sync Tx queue */
SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_SET_RESET);
}
/* Reset the RAM Buffer async Tx queue */
SK_OUT8(IoC, RB_ADDR(pPrt->PXaQOff, RB_CTRL), RB_RST_SET);
/* Reset the RAM Buffer sync Tx queue */
SK_OUT8(IoC, RB_ADDR(pPrt->PXsQOff, RB_CTRL), RB_RST_SET);
/* Reset Tx MAC FIFO */
#ifdef GENESIS
if (pAC->GIni.GIGenesis) {
/* Note: MFF_RST_SET does NOT reset the XMAC ! */
SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_RST_SET);
/* switch Link and Tx LED off, stop the LED counters */
/* Link LED is switched off by the RLMT and the Diag itself */
SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_DIS);
}
#endif /* GENESIS */
#ifdef YUKON
if (pAC->GIni.GIYukon) {
/* do the reset only if ASF is not enabled */
if (!pAC->GIni.GIAsfEnabled) {
/* Reset Tx MAC FIFO */
SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)GMF_RST_SET);
}
/* set Pause Off */
SK_OUT8(IoC, MR_ADDR(Port, GMAC_CTRL), (SK_U8)GMC_PAUSE_OFF);
}
#endif /* YUKON */
}
if ((Dir & SK_STOP_RX) != 0) {
if (CHIP_ID_YUKON_2(pAC)) {
/*
* The RX Stop command will not work for Yukon-2 if the BMU does not
* reach the end of packet and since we can't make sure that we have
* incoming data, we must reset the BMU while it is not during a DMA
* transfer. Since it is possible that the RX path is still active,
* the RX RAM buffer will be stopped first, so any possible incoming
* data will not trigger a DMA. After the RAM buffer is stopped, the
* BMU is polled until any DMA in progress is ended and only then it
* will be reset.
*/
/* disable the RAM Buffer receive queue */
SK_OUT8(IoC, RB_ADDR(pPrt->PRxQOff, RB_CTRL), RB_DIS_OP_MD);
i = 0xffff;
while (--i) {
SK_IN8(IoC, RB_ADDR(pPrt->PRxQOff, Q_RX_RSL), &rsl);
SK_IN8(IoC, RB_ADDR(pPrt->PRxQOff, Q_RX_RL), &rl);
if (rsl == rl) {
break;
}
}
/*
* If the Rx side is blocked, the above loop cannot terminate.
* But, if there was any traffic it should be terminated, now.
* However, stop the Rx BMU and the Prefetch Unit !
*/
SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR),
BMU_RST_SET | BMU_FIFO_RST);
/* reset the Rx prefetch unit */
SK_OUT32(IoC, Y2_PREF_Q_ADDR(pPrt->PRxQOff, PREF_UNIT_CTRL_REG),
PREF_UNIT_RST_SET);
}
else {
/*
* The RX Stop Command will not terminate if no buffers
* are queued in the RxD ring. But it will always reach
* the Idle state. Therefore we can use this feature to
* stop the transfer of received packets.
*/
/* stop the port's receive queue */
SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CsrStop);
i = 100;
do {
#ifdef GENESIS
if (pAC->GIni.GIGenesis) {
/* clear Rx packet arbiter timeout IRQ */
SK_OUT16(IoC, B3_PA_CTRL, (SK_U16)((Port == MAC_1) ?
PA_CLR_TO_RX1 : PA_CLR_TO_RX2));
}
#endif /* GENESIS */
RxCsr = TestStopBit(pAC, IoC, pPrt->PRxQOff);
/* timeout if i==0 (bug fix for #10748) */
if (--i == 0) {
SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_HWI_E024,
SKERR_HWI_E024MSG);
break;
}
/*
* Because of the ASIC problem report entry from 21.08.1998 it is
* required to wait until CSR_STOP is reset and CSR_SV_IDLE is set.
* (valid for GENESIS only)
*/
} while ((RxCsr & CsrTest) != CsrIdle);
/* The path data transfer activity is fully stopped now */
/* Perform a local reset of the port's Rx path */
/* Reset the PCI FIFO of the Rx queue */
SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_SET_RESET);
}
/* Reset the RAM Buffer receive queue */
SK_OUT8(IoC, RB_ADDR(pPrt->PRxQOff, RB_CTRL), RB_RST_SET);
/* Reset Rx MAC FIFO */
#ifdef GENESIS
if (pAC->GIni.GIGenesis) {
SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_RST_SET);
/* switch Rx LED off, stop the LED counter */
SkGeXmitLED(pAC, IoC, MR_ADDR(Port, RX_LED_INI), SK_LED_DIS);
}
#endif /* GENESIS */
#ifdef YUKON
if (pAC->GIni.GIYukon && !pAC->GIni.GIAsfEnabled) {
/* Reset Rx MAC FIFO */
SK_OUT8(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), (SK_U8)GMF_RST_SET);
}
#ifndef NDIS_MINIPORT_DRIVER /* temp. ifndef, remove after PM module rework*/
/* WA for Dev. #4.169 */
if ((pAC->GIni.GIChipId == CHIP_ID_YUKON ||
pAC->GIni.GIChipId == CHIP_ID_YUKON_LITE) &&
RstMode == SK_HARD_RST) {
/* set Link Control reset */
SK_OUT8(IoC, MR_ADDR(Port, GMAC_LINK_CTRL), (SK_U8)GMLC_RST_SET);
/* clear Link Control reset */
SK_OUT8(IoC, MR_ADDR(Port, GMAC_LINK_CTRL), (SK_U8)GMLC_RST_CLR);
}
#endif /* !NDIS_MINIPORT */
#endif /* YUKON */
}
} /* SkGeStopPort */
/******************************************************************************
*
* SkGeInit0() - Level 0 Initialization
*
* Description:
* - Initialize the BMU address offsets
*
* Returns:
* nothing
*/
static void SkGeInit0(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC) /* I/O Context */
{
int i;
SK_GEPORT *pPrt;
for (i = 0; i < SK_MAX_MACS; i++) {
pPrt = &pAC->GIni.GP[i];
pPrt->PState = SK_PRT_RESET;
pPrt->PPortUsage = SK_RED_LINK;
pPrt->PRxQOff = QOffTab[i].RxQOff;
pPrt->PXsQOff = QOffTab[i].XsQOff;
pPrt->PXaQOff = QOffTab[i].XaQOff;
pPrt->PCheckPar = SK_FALSE;
pPrt->PIsave = 0;
pPrt->PPrevShorts = 0;
pPrt->PLinkResCt = 0;
pPrt->PAutoNegTOCt = 0;
pPrt->PPrevRx = 0;
pPrt->PPrevFcs = 0;
pPrt->PRxLim = SK_DEF_RX_WA_LIM;
pPrt->PLinkMode = (SK_U8)SK_LMODE_AUTOFULL;
pPrt->PLinkSpeedCap = (SK_U8)SK_LSPEED_CAP_1000MBPS;
pPrt->PLinkSpeed = (SK_U8)SK_LSPEED_1000MBPS;
pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_UNKNOWN;
pPrt->PLinkModeConf = (SK_U8)SK_LMODE_AUTOSENSE;
pPrt->PFlowCtrlMode = (SK_U8)SK_FLOW_MODE_SYM_OR_REM;
pPrt->PLinkCap = (SK_U8)(SK_LMODE_CAP_HALF | SK_LMODE_CAP_FULL |
SK_LMODE_CAP_AUTOHALF | SK_LMODE_CAP_AUTOFULL);
pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN;
pPrt->PFlowCtrlCap = (SK_U8)SK_FLOW_MODE_SYM_OR_REM;
pPrt->PFlowCtrlStatus = (SK_U8)SK_FLOW_STAT_NONE;
pPrt->PMSCap = 0;
pPrt->PMSMode = (SK_U8)SK_MS_MODE_AUTO;
pPrt->PMSStatus = (SK_U8)SK_MS_STAT_UNSET;
pPrt->PLipaAutoNeg = (SK_U8)SK_LIPA_UNKNOWN;
pPrt->PAutoNegFail = SK_FALSE;
pPrt->PHWLinkUp = SK_FALSE;
pPrt->PLinkBroken = SK_TRUE; /* See WA code */
pPrt->PPhyPowerState = PHY_PM_OPERATIONAL_MODE;
pPrt->PMacColThres = TX_COL_DEF;
pPrt->PMacJamLen = TX_JAM_LEN_DEF;
pPrt->PMacJamIpgVal = TX_JAM_IPG_DEF;
pPrt->PMacJamIpgData = TX_IPG_JAM_DEF;
pPrt->PMacBackOffLim = TX_BOF_LIM_DEF;
pPrt->PMacDataBlind = DATA_BLIND_DEF;
pPrt->PMacIpgData = IPG_DATA_DEF;
pPrt->PMacLimit4 = SK_FALSE;
}
pAC->GIni.GILedBlinkCtrl = (SK_U16)OemConfig.Value;
pAC->GIni.GIChipCap = 0;
for (i = 0; i < 4; i++) {
pAC->GIni.HwF.Features[i]= 0x00000000;
pAC->GIni.HwF.OnMask[i] = 0x00000000;
pAC->GIni.HwF.OffMask[i] = 0x00000000;
}
} /* SkGeInit0*/
#ifdef SK_PCI_RESET
/******************************************************************************
*
* SkGePciReset() - Reset PCI interface
*
* Description:
* o Read PCI configuration.
* o Change power state to 3.
* o Change power state to 0.
* o Restore PCI configuration.
*
* Returns:
* 0: Success.
* 1: Power state could not be changed to 3.
*/
static int SkGePciReset(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC) /* I/O Context */
{
int i;
SK_U16 PmCtlSts;
SK_U32 Bp1;
SK_U32 Bp2;
SK_U16 PciCmd;
SK_U8 Cls;
SK_U8 Lat;
SK_U8 ConfigSpace[PCI_CFG_SIZE];
/*
* Note: Switching to D3 state is like a software reset.
* Switching from D3 to D0 is a hardware reset.
* We have to save and restore the configuration space.
*/
for (i = 0; i < PCI_CFG_SIZE; i++) {
SkPciReadCfgDWord(pAC, i*4, &ConfigSpace[i]);
}
/* We know the RAM Interface Arbiter is enabled. */
SkPciWriteCfgWord(pAC, PCI_PM_CTL_STS, PCI_PM_STATE_D3);
SkPciReadCfgWord(pAC, PCI_PM_CTL_STS, &PmCtlSts);
if ((PmCtlSts & PCI_PM_STATE_MSK) != PCI_PM_STATE_D3) {
return(1);
}
/* Return to D0 state. */
SkPciWriteCfgWord(pAC, PCI_PM_CTL_STS, PCI_PM_STATE_D0);
/* Check for D0 state. */
SkPciReadCfgWord(pAC, PCI_PM_CTL_STS, &PmCtlSts);
if ((PmCtlSts & PCI_PM_STATE_MSK) != PCI_PM_STATE_D0) {
return(1);
}
/* Check PCI Config Registers. */
SkPciReadCfgWord(pAC, PCI_COMMAND, &PciCmd);
SkPciReadCfgByte(pAC, PCI_CACHE_LSZ, &Cls);
SkPciReadCfgDWord(pAC, PCI_BASE_1ST, &Bp1);
/*
* Compute the location in PCI config space of BAR2
* relativ to the location of BAR1
*/
if ((Bp1 & PCI_MEM_TYP_MSK) == PCI_MEM64BIT) {
/* BAR1 is 64 bits wide */
i = 8;
}
else {
i = 4;
}
SkPciReadCfgDWord(pAC, PCI_BASE_1ST + i, &Bp2);
SkPciReadCfgByte(pAC, PCI_LAT_TIM, &Lat);
if (PciCmd != 0 || Cls != 0 || (Bp1 & 0xfffffff0L) != 0 || Bp2 != 1 ||
Lat != 0) {
return(1);
}
/* Restore PCI Config Space. */
for (i = 0; i < PCI_CFG_SIZE; i++) {
SkPciWriteCfgDWord(pAC, i*4, ConfigSpace[i]);
}
return(0);
} /* SkGePciReset */
#endif /* SK_PCI_RESET */
#ifndef SK_SLIM
/******************************************************************************
*
* SkGeSetUpSupFeatures() - Collect Feature List for HW_FEATURE Macro
*
* Description:
* This function collects the available features and required
* deviation services of the Adapter and provides these
* information in the GIHwF struct. This information is used as
* default value and may be overritten by the driver using the
* SET_HW_FEATURE_MASK() macro in its Init0 phase.
*
* Notice:
* Using the On and Off mask: Never switch on the same bit in both
* masks simultaneously. However, if doing the Off mask will win.
*
* Returns:
* nothing
*/
static void SkGeSetUpSupFeatures(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC) /* I/O Context */
{
int i;
SK_U16 Word;
switch (pAC->GIni.GIChipId) {
case CHIP_ID_YUKON_EC:
if (pAC->GIni.GIChipRev == CHIP_REV_YU_EC_A1) {
/* A0/A1 */
pAC->GIni.HwF.Features[HW_DEV_LIST] =
HWF_WA_DEV_42 | HWF_WA_DEV_46 | HWF_WA_DEV_43_418 |
HWF_WA_DEV_420 | HWF_WA_DEV_423 |
HWF_WA_DEV_424 | HWF_WA_DEV_425 | HWF_WA_DEV_427 |
HWF_WA_DEV_428 | HWF_WA_DEV_483 | HWF_WA_DEV_4109 |
HWF_WA_DEV_4152| HWF_WA_DEV_4167;
}
else {
/* A2/A3 */
pAC->GIni.HwF.Features[HW_DEV_LIST] =
HWF_WA_DEV_424 | HWF_WA_DEV_425 | HWF_WA_DEV_427 |
HWF_WA_DEV_428 | HWF_WA_DEV_483 | HWF_WA_DEV_4109 |
HWF_WA_DEV_4152| HWF_WA_DEV_4167;
}
break;
case CHIP_ID_YUKON_FE:
pAC->GIni.HwF.Features[HW_DEV_LIST] =
HWF_WA_DEV_427 | HWF_WA_DEV_4109 |
HWF_WA_DEV_4152| HWF_WA_DEV_4167;
break;
case CHIP_ID_YUKON_XL:
switch (pAC->GIni.GIChipRev) {
case CHIP_REV_YU_XL_A0: /* still needed for Diag */
pAC->GIni.HwF.Features[HW_DEV_LIST] =
HWF_WA_DEV_427 | HWF_WA_DEV_463 | HWF_WA_DEV_472 |
HWF_WA_DEV_479 | HWF_WA_DEV_483 | HWF_WA_DEV_4115 |
HWF_WA_DEV_4152| HWF_WA_DEV_4167;
break;
case CHIP_REV_YU_XL_A1:
pAC->GIni.HwF.Features[HW_DEV_LIST] =
HWF_WA_DEV_427 | HWF_WA_DEV_483 | HWF_WA_DEV_4109 |
HWF_WA_DEV_4115| HWF_WA_DEV_4152| HWF_WA_DEV_4167;
break;
case CHIP_REV_YU_XL_A2:
pAC->GIni.HwF.Features[HW_DEV_LIST] =
HWF_WA_DEV_427 | HWF_WA_DEV_483 | HWF_WA_DEV_4109 |
HWF_WA_DEV_4115 | HWF_WA_DEV_4167;
break;
case CHIP_REV_YU_XL_A3:
pAC->GIni.HwF.Features[HW_DEV_LIST] =
HWF_WA_DEV_427 | HWF_WA_DEV_483 | HWF_WA_DEV_4109 |
HWF_WA_DEV_4115;
break;
}
break;
case CHIP_ID_YUKON_EC_U:
if (pAC->GIni.GIChipRev == CHIP_REV_YU_EC_U_A0) {
pAC->GIni.HwF.Features[HW_DEV_LIST] =
HWF_WA_DEV_427 | HWF_WA_DEV_483 | HWF_WA_DEV_4109;
}
else if (pAC->GIni.GIChipRev == CHIP_REV_YU_EC_U_A1) {
pAC->GIni.HwF.Features[HW_DEV_LIST] =
HWF_WA_DEV_427 | HWF_WA_DEV_4109 | HWF_WA_DEV_4185;
/* check for Rev. A1 */
SK_IN16(IoC, Q_ADDR(Q_XA1, Q_WM), &Word);
if (Word == 0) {
pAC->GIni.HwF.Features[HW_DEV_LIST] |=
HWF_WA_DEV_4185CS | HWF_WA_DEV_4200;
}
}
break;
}
for (i = 0; i < 4; i++) {
pAC->GIni.HwF.Features[i] =
(pAC->GIni.HwF.Features[i] | pAC->GIni.HwF.OnMask[i]) &
~pAC->GIni.HwF.OffMask[i];
}
} /* SkGeSetUpSupFeatures */
#endif /* !SK_SLIM */
/******************************************************************************
*
* SkGeInit1() - Level 1 Initialization
*
* Description:
* o Do a software reset.
* o Clear all reset bits.
* o Verify that the detected hardware is present.
* Return an error if not.
* o Get the hardware configuration
* + Read the number of MACs/Ports.
* + Read the RAM size.
* + Read the PCI Revision Id.
* + Find out the adapters host clock speed
* + Read and check the PHY type
*
* Returns:
* 0: success
* 5: Unexpected PHY type detected
* 6: HW self test failed
*/
static int SkGeInit1(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC) /* I/O Context */
{
SK_U8 Byte;
SK_U16 Word;
SK_U32 CtrlStat;
SK_U32 VauxAvail;
SK_U32 DWord;
SK_U32 Our1;
SK_U32 PowerDownBit;
SK_BOOL FiberType;
SK_GEPORT *pPrt;
int RetVal;
int i, j;
RetVal = 0;
/* save CLK_RUN & ASF_ENABLE bits (YUKON-Lite, YUKON-EC) */
SK_IN32(IoC, B0_CTST, &CtrlStat);
#ifdef SK_PCI_RESET
(void)SkGePciReset(pAC, IoC);
#endif /* SK_PCI_RESET */
/* release the SW-reset */
/* Important: SW-reset has to be cleared here, to ensure
* the CHIP_ID can be read IO-mapped based, too -
* remember the RAP register can only be written if
* SW-reset is cleared.
*/
SK_OUT8(IoC, B0_CTST, CS_RST_CLR);
/* read Chip Identification Number */
SK_IN8(IoC, B2_CHIP_ID, &Byte);
pAC->GIni.GIChipId = Byte;
pAC->GIni.GIAsfEnabled = SK_FALSE;
/* ASF support only for Yukon-2 */
if ((pAC->GIni.GIChipId >= CHIP_ID_YUKON_XL) &&
(pAC->GIni.GIChipId <= CHIP_ID_YUKON_EC)) {
#ifdef SK_ASF
if ((CtrlStat & Y2_ASF_ENABLE) != 0) {
/* do the SW-reset only if ASF is not enabled */
pAC->GIni.GIAsfEnabled = SK_TRUE;
}
#else /* !SK_ASF */
SK_IN8(IoC, B28_Y2_ASF_STAT_CMD, &Byte);
pAC->GIni.GIAsfRunning = Byte & Y2_ASF_RUNNING;
/* put ASF system in reset state */
SK_OUT8(IoC, B28_Y2_ASF_STAT_CMD, (SK_U8)Y2_ASF_RESET);
/* disable ASF Unit */
SK_OUT16(IoC, B0_CTST, Y2_ASF_DISABLE);
#endif /* !SK_ASF */
}
if (!pAC->GIni.GIAsfEnabled) {
/* Yukon-2: required for Diag and Power Management */
/* set the SW-reset */
SK_OUT8(IoC, B0_CTST, CS_RST_SET);
/* release the SW-reset */
SK_OUT8(IoC, B0_CTST, CS_RST_CLR);
}
/* enable Config Write */
SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
/* reset all error bits in the PCI STATUS register */
/*
* Note: PCI Cfg cycles cannot be used, because they are not
* available on some platforms after 'boot time'.
*/
SK_IN16(IoC, PCI_C(pAC, PCI_STATUS), &Word);
SK_OUT16(IoC, PCI_C(pAC, PCI_STATUS), Word | (SK_U16)PCI_ERRBITS);
/* release Master Reset */
SK_OUT8(IoC, B0_CTST, CS_MRST_CLR);
#ifdef CLK_RUN
CtrlStat |= CS_CLK_RUN_ENA;
/* restore CLK_RUN bits */
SK_OUT16(IoC, B0_CTST, (SK_U16)(CtrlStat &
(CS_CLK_RUN_HOT | CS_CLK_RUN_RST | CS_CLK_RUN_ENA)));
#endif /* CLK_RUN */
if ((pAC->GIni.GIChipId >= CHIP_ID_YUKON_XL) &&
(pAC->GIni.GIChipId <= CHIP_ID_YUKON_FE)) {
pAC->GIni.GIYukon2 = SK_TRUE;
pAC->GIni.GIValIrqMask = Y2_IS_ALL_MSK;
pAC->GIni.GIValHwIrqMask = Y2_HWE_ALL_MSK;
VauxAvail = Y2_VAUX_AVAIL;
SK_IN32(IoC, PCI_C(pAC, PCI_OUR_STATUS), &DWord);
if ((DWord & PCI_OS_PCI_X) != 0) {
#ifndef SK_SLIM
/* this is a PCI / PCI-X bus */
if ((DWord & PCI_OS_PCIX) != 0) {
/* this is a PCI-X bus */
pAC->GIni.GIPciBus = SK_PCIX_BUS;
/* PCI-X is always 64-bit wide */
pAC->GIni.GIPciSlot64 = SK_TRUE;
pAC->GIni.GIPciMode = (SK_U8)(PCI_OS_SPEED(DWord));
}
else {
/* this is a conventional PCI bus */
pAC->GIni.GIPciBus = SK_PCI_BUS;
SK_IN16(IoC, PCI_C(pAC, PCI_OUR_REG_2), &Word);
/* check if 64-bit width is used */
pAC->GIni.GIPciSlot64 = (SK_BOOL)
(((DWord & PCI_OS_PCI64B) != 0) &&
((Word & PCI_USEDATA64) != 0));
/* check if 66 MHz PCI Clock is active */
pAC->GIni.GIPciClock66 = (SK_BOOL)((DWord & PCI_OS_PCI66M) != 0);
}
#endif /* !SK_SLIM */
}
else {
/* this is a PEX bus */
pAC->GIni.GIPciBus = SK_PEX_BUS;
/* clear any PEX errors */
SK_OUT32(IoC, PCI_C(pAC, PEX_UNC_ERR_STAT), 0xffffffffUL);
SK_IN32(IoC, PCI_C(pAC, PEX_UNC_ERR_STAT), &DWord);
if ((DWord & PEX_RX_OV) != 0) {
/* Dev #4.205 occured */
pAC->GIni.GIValHwIrqMask &= ~Y2_IS_PCI_EXP;
pAC->GIni.GIValIrqMask &= ~Y2_IS_HW_ERR;
}
SK_IN16(IoC, PCI_C(pAC, PEX_LNK_STAT), &Word);
pAC->GIni.GIPexWidth = (SK_U8)((Word & PEX_LS_LINK_WI_MSK) >> 4);
}
/*
* Yukon-2 chips family has a different way of providing
* the number of MACs available
*/
pAC->GIni.GIMacsFound = 1;
/* get HW Resources */
SK_IN8(IoC, B2_Y2_HW_RES, &Byte);
if (CHIP_ID_YUKON_2(pAC)) {
/*
* OEM config value is overwritten and should not
* be used for Yukon-2
*/
pAC->GIni.GILedBlinkCtrl |= SK_ACT_LED_BLINK;
#ifndef SK_SLIM
if (pAC->GIni.GIChipId == CHIP_ID_YUKON_EC_U) {
/* LED Configuration is stored in GPIO */
SK_IN8(IoC, B2_GP_IO, &Byte);
if (CFG_LED_MODE(Byte) == CFG_LED_LINK_MUX_P60) {
pAC->GIni.GILedBlinkCtrl |= SK_LED_LINK_MUX_P60;
}
}
#endif /* !SK_SLIM */
if (CFG_LED_MODE(Byte) == CFG_LED_DUAL_ACT_LNK) {
pAC->GIni.GILedBlinkCtrl |= SK_DUAL_LED_ACT_LNK;
}
}
/* save HW Resources / Application Information */
pAC->GIni.GIHwResInfo = Byte;
if ((Byte & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) {
SK_IN8(IoC, B2_Y2_CLK_GATE, &Byte);
if (!(Byte & Y2_STATUS_LNK2_INAC)) {
/* Link 2 activ */
pAC->GIni.GIMacsFound++;
}
}
#ifdef VCPU
if (pAC->GIni.GIChipId == CHIP_ID_YUKON_XL) {
/* temporary WA for reported number of links */
pAC->GIni.GIMacsFound = 2;
}
#endif /* VCPU */
/* read Chip Revision */
SK_IN8(IoC, B2_MAC_CFG, &Byte);
pAC->GIni.GIChipCap = Byte & 0x0f;
}
else {
pAC->GIni.GIYukon2 = SK_FALSE;
pAC->GIni.GIValIrqMask = IS_ALL_MSK;
pAC->GIni.GIValHwIrqMask = 0; /* not activated */
VauxAvail = CS_VAUX_AVAIL;
/* read number of MACs and Chip Revision */
SK_IN8(IoC, B2_MAC_CFG, &Byte);
pAC->GIni.GIMacsFound = (Byte & CFG_SNG_MAC) ? 1 : 2;
}
/* get Chip Revision Number */
pAC->GIni.GIChipRev = (SK_U8)((Byte & CFG_CHIP_R_MSK) >> 4);
#ifndef SK_DIAG
if (pAC->GIni.GIChipId == CHIP_ID_YUKON_XL &&
pAC->GIni.GIChipRev == CHIP_REV_YU_XL_A0) {
/* Yukon-2 Chip Rev. A0 */
return(6);
}
#endif /* !SK_DIAG */
/* read the adapters RAM size */
SK_IN8(IoC, B2_E_0, &Byte);
pAC->GIni.GIGenesis = SK_FALSE;
pAC->GIni.GIYukon = SK_FALSE;
pAC->GIni.GIYukonLite = SK_FALSE;
pAC->GIni.GIVauxAvail = SK_FALSE;
#ifdef GENESIS
if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
pAC->GIni.GIGenesis = SK_TRUE;
if (Byte == (SK_U8)3) {
/* special case: 4 x 64k x 36, offset = 0x80000 */
pAC->GIni.GIRamSize = 1024;
pAC->GIni.GIRamOffs = (SK_U32)512 * 1024;
}
else {
pAC->GIni.GIRamSize = (int)Byte * 512;
pAC->GIni.GIRamOffs = 0;
}
/* all GENESIS adapters work with 53.125 MHz host clock */
pAC->GIni.GIHstClkFact = SK_FACT_53;
/* set Descr. Poll Timer Init Value to 250 ms */
pAC->GIni.GIPollTimerVal =
SK_DPOLL_DEF * (SK_U32)pAC->GIni.GIHstClkFact / 100;
}
#endif /* GENESIS */
#ifdef YUKON
if (pAC->GIni.GIChipId != CHIP_ID_GENESIS) {
pAC->GIni.GIYukon = SK_TRUE;
pAC->GIni.GIRamSize = (Byte == (SK_U8)0) ? 128 : (int)Byte * 4;
#ifndef SK_SLIM
pAC->GIni.GIRamOffs = 0;
/* WA for Yukon chip Rev. A */
pAC->GIni.GIWolOffs = (pAC->GIni.GIChipId == CHIP_ID_YUKON &&
pAC->GIni.GIChipRev == 0) ? WOL_REG_OFFS : 0;
/* get PM Capabilities of PCI config space */
SK_IN16(IoC, PCI_C(pAC, PCI_PM_CAP_REG), &Word);
/* check if VAUX is available */
if (((CtrlStat & VauxAvail) != 0) &&
/* check also if PME from D3cold is set */
((Word & PCI_PME_D3C_SUP) != 0)) {
/* set entry in GE init struct */
pAC->GIni.GIVauxAvail = SK_TRUE;
}
#endif /* !SK_SLIM */
if (!CHIP_ID_YUKON_2(pAC)) {
if (pAC->GIni.GIChipId == CHIP_ID_YUKON_LITE) {
/* this is Rev. A1 */
pAC->GIni.GIYukonLite = SK_TRUE;
}
#ifndef SK_SLIM
else {
/* save Flash-Address Register */
SK_IN32(IoC, B2_FAR, &DWord);
/* test Flash-Address Register */
SK_OUT8(IoC, B2_FAR + 3, 0xff);
SK_IN8(IoC, B2_FAR + 3, &Byte);
if (Byte != 0) {
/* this is Rev. A0 */
pAC->GIni.GIYukonLite = SK_TRUE;
/* restore Flash-Address Register */
SK_OUT32(IoC, B2_FAR, DWord);
}
}
#endif /* !SK_SLIM */
}
else {
/* Check for CLS = 0 (dev. #4.55) */
if (pAC->GIni.GIPciBus != SK_PEX_BUS) {
/* PCI and PCI-X */
SK_IN8(IoC, PCI_C(pAC, PCI_CACHE_LSZ), &Byte);
if (Byte == 0) {
/* set CLS to 2 if configured to 0 */
SK_OUT8(IoC, PCI_C(pAC, PCI_CACHE_LSZ), 2);
}
if (pAC->GIni.GIPciBus == SK_PCIX_BUS) {
/* set Cache Line Size opt. */
SK_IN32(IoC, PCI_C(pAC, PCI_OUR_REG_1), &DWord);
DWord |= PCI_CLS_OPT;
SK_OUT32(IoC, PCI_C(pAC, PCI_OUR_REG_1), DWord);
}
}
}
/* switch power to VCC (WA for VAUX problem) */
SK_OUT8(IoC, B0_POWER_CTRL, (SK_U8)(PC_VAUX_ENA | PC_VCC_ENA |
PC_VAUX_OFF | PC_VCC_ON));
Byte = 0;
if (CHIP_ID_YUKON_2(pAC)) {
switch (pAC->GIni.GIChipId) {
/* PEX adapters work with different host clock */
case CHIP_ID_YUKON_EC:
case CHIP_ID_YUKON_EC_U:
/* Yukon-EC works with 125 MHz host clock */
pAC->GIni.GIHstClkFact = SK_FACT_125;
break;
case CHIP_ID_YUKON_FE:
/* Yukon-FE works with 100 MHz host clock */
pAC->GIni.GIHstClkFact = SK_FACT_100;
break;
case CHIP_ID_YUKON_XL:
/* all Yukon-2 adapters work with 156 MHz host clock */
pAC->GIni.GIHstClkFact = 2 * SK_FACT_78;
if (pAC->GIni.GIChipRev > CHIP_REV_YU_XL_A1) {
/* enable bits are inverted */
Byte = (SK_U8)(Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
}
break;
default:
SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E006,
SKERR_HWI_E006MSG);
}
pAC->GIni.GIPollTimerVal =
SK_DPOLL_DEF_Y2 * (SK_U32)pAC->GIni.GIHstClkFact / 100;
/* set power down bit */
PowerDownBit = PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD;
/* disable Core Clock Division, set Clock Select to 0 (Yukon-2) */
SK_OUT32(IoC, B2_Y2_CLK_CTRL, Y2_CLK_DIV_DIS);
/* enable MAC/PHY, PCI and Core Clock for both Links */
SK_OUT8(IoC, B2_Y2_CLK_GATE, Byte);
}
else {
/* YUKON adapters work with 78 MHz host clock */
pAC->GIni.GIHstClkFact = SK_FACT_78;
pAC->GIni.GIPollTimerVal = SK_DPOLL_MAX; /* 215 ms */
/* read the Interrupt source */
SK_IN32(IoC, B0_ISRC, &DWord);
if ((DWord & IS_HW_ERR) != 0) {
/* read the HW Error Interrupt source */
SK_IN32(IoC, B0_HWE_ISRC, &DWord);
if ((DWord & IS_IRQ_SENSOR) != 0) {
/* disable HW Error IRQ */
pAC->GIni.GIValIrqMask &= ~IS_HW_ERR;
}
}
/* set power down bit */
PowerDownBit = PCI_PHY_COMA;
}
SK_IN32(IoC, PCI_C(pAC, PCI_OUR_REG_1), &Our1);
Our1 &= ~PowerDownBit;
if (pAC->GIni.GIChipId == CHIP_ID_YUKON_XL &&
pAC->GIni.GIChipRev > CHIP_REV_YU_XL_A1) {
/* deassert Low Power for 1st PHY */
Our1 |= PCI_Y2_PHY1_COMA;
if (pAC->GIni.GIMacsFound > 1) {
/* deassert Low Power for 2nd PHY */
Our1 |= PCI_Y2_PHY2_COMA;
}
}
else if (pAC->GIni.GIChipId == CHIP_ID_YUKON_EC_U) {
/* enable HW WOL */
SK_OUT16(IoC, B0_CTST, (SK_U16)Y2_HW_WOL_ON);
/* enable all clocks */
SK_OUT32(IoC, PCI_C(pAC, PCI_OUR_REG_3), 0);
SK_IN32(IoC, PCI_C(pAC, PCI_OUR_REG_4), &DWord);
DWord &= P_ASPM_CONTROL_MSK;
/* set all bits to 0 except bits 15..12 */
SK_OUT32(IoC, PCI_C(pAC, PCI_OUR_REG_4), DWord);
/* set to default value */
SK_OUT32(IoC, PCI_C(pAC, PCI_OUR_REG_5), 0);
}
/* release PHY from PowerDown/COMA Mode */
SK_OUT32(IoC, PCI_C(pAC, PCI_OUR_REG_1), Our1);
if (!pAC->GIni.GIAsfEnabled) {
for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
/* set Link Control reset */
SK_OUT8(IoC, MR_ADDR(i, GMAC_LINK_CTRL), (SK_U8)GMLC_RST_SET);
/* clear Link Control reset */
SK_OUT8(IoC, MR_ADDR(i, GMAC_LINK_CTRL), (SK_U8)GMLC_RST_CLR);
}
}
}
#endif /* YUKON */
SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
#ifndef SK_SLIM
if (!CHIP_ID_YUKON_2(pAC)) {
/* this is a conventional PCI bus */
pAC->GIni.GIPciBus = SK_PCI_BUS;
/* check if 64-bit PCI Slot is present */
pAC->GIni.GIPciSlot64 = (SK_BOOL)((CtrlStat & CS_BUS_SLOT_SZ) != 0);
/* check if 66 MHz PCI Clock is active */
pAC->GIni.GIPciClock66 = (SK_BOOL)((CtrlStat & CS_BUS_CLOCK) != 0);
}
/* read PCI HW Revision Id. */
SK_IN8(IoC, PCI_C(pAC, PCI_REV_ID), &Byte);
pAC->GIni.GIPciHwRev = Byte;
/* read connector type */
SK_IN8(IoC, B2_CONN_TYP, &pAC->GIni.GIConTyp);
#endif /* !SK_SLIM */
/* read the PMD type */
SK_IN8(IoC, B2_PMD_TYP, &Byte);
pAC->GIni.GIPmdTyp = Byte;
FiberType = (Byte == 'L' || Byte == 'S' || Byte == 'P');
pAC->GIni.GICopperType = (SK_BOOL)(Byte == 'T' || Byte == '1' ||
(pAC->GIni.GIYukon2 && !FiberType));
/* read the PHY type (Yukon and Genesis) */
SK_IN8(IoC, B2_E_1, &Byte);
Byte &= 0x0f; /* the PHY type is stored in the lower nibble */
for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
pPrt = &pAC->GIni.GP[i];
/* get the MAC addresses */
for (j = 0; j < 3; j++) {
SK_IN16(IoC, B2_MAC_1 + i * 8 + j * 2, &pPrt->PMacAddr[j]);
}
#ifdef GENESIS
if (pAC->GIni.GIGenesis) {
switch (Byte) {
case SK_PHY_XMAC:
pPrt->PhyAddr = PHY_ADDR_XMAC;
break;
case SK_PHY_BCOM:
pPrt->PhyAddr = PHY_ADDR_BCOM;
pPrt->PMSCap = (SK_U8)(SK_MS_CAP_AUTO |
SK_MS_CAP_MASTER | SK_MS_CAP_SLAVE);
break;
#ifdef OTHER_PHY
case SK_PHY_LONE:
pPrt->PhyAddr = PHY_ADDR_LONE;
break;
case SK_PHY_NAT:
pPrt->PhyAddr = PHY_ADDR_NAT;
break;
#endif /* OTHER_PHY */
default:
/* ERROR: unexpected PHY type detected */
RetVal = 5;
}
}
#endif /* GENESIS */
#ifdef YUKON
if (pAC->GIni.GIYukon) {
if (((Byte < (SK_U8)SK_PHY_MARV_COPPER) || pAC->GIni.GIYukon2) &&
!FiberType) {
/* if this field is not initialized */
Byte = (SK_U8)SK_PHY_MARV_COPPER;
pAC->GIni.GICopperType = SK_TRUE;
}
pPrt->PhyAddr = PHY_ADDR_MARV;
if (pAC->GIni.GICopperType) {
if (pAC->GIni.GIChipId == CHIP_ID_YUKON_FE ||
(pAC->GIni.GIChipId == CHIP_ID_YUKON_EC &&
pAC->GIni.GIChipCap == 2)) {
pPrt->PLinkSpeedCap = (SK_U8)(SK_LSPEED_CAP_100MBPS |
SK_LSPEED_CAP_10MBPS);
pAC->GIni.GIRamSize = 4;
}
else {
pPrt->PLinkSpeedCap = (SK_U8)(SK_LSPEED_CAP_1000MBPS |
SK_LSPEED_CAP_100MBPS | SK_LSPEED_CAP_10MBPS |
SK_LSPEED_CAP_AUTO);
}
pPrt->PLinkSpeed = (SK_U8)SK_LSPEED_AUTO;
pPrt->PMSCap = (SK_U8)(SK_MS_CAP_AUTO |
SK_MS_CAP_MASTER | SK_MS_CAP_SLAVE);
}
else {
Byte = (SK_U8)SK_PHY_MARV_FIBER;
}
}
/* clear TWSI IRQ */
SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ);
#endif /* YUKON */
pPrt->PhyType = (int)Byte;
SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
("PHY type: %d PHY addr: %04x\n",
Byte, pPrt->PhyAddr));
}
/* get MAC Type & set function pointers dependent on */
#ifdef GENESIS
if (pAC->GIni.GIGenesis) {
pAC->GIni.GIMacType = SK_MAC_XMAC;
pAC->GIni.GIFunc.pFnMacUpdateStats = SkXmUpdateStats;
pAC->GIni.GIFunc.pFnMacStatistic = SkXmMacStatistic;
pAC->GIni.GIFunc.pFnMacResetCounter = SkXmResetCounter;
pAC->GIni.GIFunc.pFnMacOverflow = SkXmOverflowStatus;
#ifdef SK_DIAG
pAC->GIni.GIFunc.pFnMacPhyRead = SkXmPhyRead;
pAC->GIni.GIFunc.pFnMacPhyWrite = SkXmPhyWrite;
#else /* SK_DIAG */
pAC->GIni.GIFunc.pSkGeSirqIsr = SkGeYuSirqIsr;
#endif /* !SK_DIAG */
}
#endif /* GENESIS */
#ifdef YUKON
if (pAC->GIni.GIYukon) {
#ifndef SK_SLIM
pAC->GIni.GIMacType = SK_MAC_GMAC;
pAC->GIni.GIFunc.pFnMacUpdateStats = SkGmUpdateStats;
pAC->GIni.GIFunc.pFnMacStatistic = SkGmMacStatistic;
pAC->GIni.GIFunc.pFnMacResetCounter = SkGmResetCounter;
pAC->GIni.GIFunc.pFnMacOverflow = SkGmOverflowStatus;
#endif /* !SK_SLIM */
#ifdef SK_DIAG
pAC->GIni.GIFunc.pFnMacPhyRead = SkGmPhyRead;
pAC->GIni.GIFunc.pFnMacPhyWrite = SkGmPhyWrite;
#else /* SK_DIAG */
if (CHIP_ID_YUKON_2(pAC)) {
pAC->GIni.GIFunc.pSkGeSirqIsr = SkYuk2SirqIsr;
}
else {
pAC->GIni.GIFunc.pSkGeSirqIsr = SkGeYuSirqIsr;
}
#endif /* !SK_DIAG */
#ifdef SPECIAL_HANDLING
if (pAC->GIni.GIChipId == CHIP_ID_YUKON) {
/* check HW self test result */
SK_IN8(IoC, B2_E_3, &Byte);
if (Byte & B2_E3_RES_MASK) {
RetVal = 6;
}
}
#endif
}
#endif /* YUKON */
#ifndef SK_SLIM
SkGeSetUpSupFeatures(pAC, IoC);
#endif /* !SK_SLIM */
return(RetVal);
} /* SkGeInit1 */
/******************************************************************************
*
* SkGeInit2() - Level 2 Initialization
*
* Description:
* - start the Blink Source Counter
* - start the Descriptor Poll Timer
* - configure the MAC-Arbiter
* - configure the Packet-Arbiter
* - enable the Tx Arbiters
* - enable the RAM Interface Arbiter
*
* Returns:
* nothing
*/
static void SkGeInit2(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC) /* I/O Context */
{
#ifdef YUKON
SK_U16 Word;
#if (!defined(SK_SLIM) && !defined(SK_DIAG))
SK_EVPARA Para;
#endif /* !SK_SLIM && !SK_DIAG */
#endif /* YUKON */
#ifdef GENESIS
SK_U32 DWord;
#endif /* GENESIS */
int i;
/* start the Descriptor Poll Timer */
if (pAC->GIni.GIPollTimerVal != 0) {
if (pAC->GIni.GIPollTimerVal > SK_DPOLL_MAX) {
pAC->GIni.GIPollTimerVal = SK_DPOLL_MAX;
SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E017, SKERR_HWI_E017MSG);
}
SK_OUT32(IoC, B28_DPT_INI, pAC->GIni.GIPollTimerVal);
SK_OUT8(IoC, B28_DPT_CTRL, DPT_START);
}
#ifdef GENESIS
if (pAC->GIni.GIGenesis) {
/* start the Blink Source Counter */
DWord = SK_BLK_DUR * (SK_U32)pAC->GIni.GIHstClkFact / 100;
SK_OUT32(IoC, B2_BSC_INI, DWord);
SK_OUT8(IoC, B2_BSC_CTRL, BSC_START);
/*
* Configure the MAC Arbiter and the Packet Arbiter.
* They will be started once and never be stopped.
*/
SkGeInitMacArb(pAC, IoC);
SkGeInitPktArb(pAC, IoC);
}
#endif /* GENESIS */
#ifdef xSK_DIAG
if (pAC->GIni.GIYukon) {
/* start Time Stamp Timer */
SK_OUT8(IoC, GMAC_TI_ST_CTRL, (SK_U8)GMT_ST_START);
}
#endif /* SK_DIAG */
/* enable the Tx Arbiters */
for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
SK_OUT8(IoC, MR_ADDR(i, TXA_CTRL), TXA_ENA_ARB);
}
/* enable the RAM Interface Arbiter */
SkGeInitRamIface(pAC, IoC);
#ifdef YUKON
if (CHIP_ID_YUKON_2(pAC)) {
if (pAC->GIni.GIPciBus == SK_PEX_BUS) {
SK_IN16(IoC, PCI_C(pAC, PEX_DEV_CTRL), &Word);
/* change Max. Read Request Size to 2048 bytes */
Word &= ~PEX_DC_MAX_RRS_MSK;
Word |= PEX_DC_MAX_RD_RQ_SIZE(4);
SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
SK_OUT16(IoC, PCI_C(pAC, PEX_DEV_CTRL), Word);
#ifdef REPLAY_TIMER
if (pAC->GIni.GIChipId == CHIP_ID_YUKON_EC) {
/* PEX Ack Reply Timeout to 40 us */
SK_OUT16(IoC, PCI_C(pAC, PEX_ACK_RPLY_TOX1), 0x2710);
}
#endif
SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
#if (!defined(SK_SLIM) && !defined(SK_DIAG))
SK_IN16(IoC, PCI_C(pAC, PEX_LNK_CAP), &Word);
Word = (Word & PEX_CAP_MAX_WI_MSK) >> 4;
/* compare PEX Negotiated Link Width against max. capabil */
if (pAC->GIni.GIPexWidth != (SK_U8)Word) {
SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
("PEX negotiated Link width is: %d, exp.: %d\n",
pAC->GIni.GIPexWidth, Word));
#ifndef NDIS_MINIPORT_DRIVER
SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_HWI_E026,
SKERR_HWI_E026MSG);
#endif
Para.Para64 = 0;
SkEventQueue(pAC, SKGE_DRV, SK_DRV_PEX_LINK_WIDTH, Para);
}
#endif /* !SK_SLIM && !SK_DIAG */
}
/*
* Writing the HW Error Mask Reg. will not generate an IRQ
* as long as the B0_IMSK is not set by the driver.
*/
SK_OUT32(IoC, B0_HWE_IMSK, pAC->GIni.GIValHwIrqMask);
}
#endif /* YUKON */
} /* SkGeInit2 */
/******************************************************************************
*
* SkGeInit() - Initialize the GE Adapter with the specified level.
*
* Description:
* Level 0: Initialize the Module structures.
* Level 1: Generic Hardware Initialization. The IOP/MemBase pointer has
* to be set before calling this level.
*
* o Do a software reset.
* o Clear all reset bits.
* o Verify that the detected hardware is present.
* Return an error if not.
* o Get the hardware configuration
* + Set GIMacsFound with the number of MACs.
* + Store the RAM size in GIRamSize.
* + Save the PCI Revision ID in GIPciHwRev.
* o return an error
* if Number of MACs > SK_MAX_MACS
*
* After returning from Level 0 the adapter
* may be accessed with I/O operations.
*
* Level 2: start the Blink Source Counter
*
* Returns:
* 0: success
* 1: Number of MACs exceeds SK_MAX_MACS (after level 1)
* 2: Adapter not present or not accessible
* 3: Illegal initialization level
* 4: Initialization level 1 call missing
* 5: Unexpected PHY type detected
* 6: HW self test failed
*/
int SkGeInit(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC, /* I/O Context */
int Level) /* Initialization Level */
{
int RetVal; /* return value */
SK_U32 DWord;
RetVal = 0;
SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
("SkGeInit(Level %d)\n", Level));
switch (Level) {
case SK_INIT_DATA:
/* Initialization Level 0 */
SkGeInit0(pAC, IoC);
pAC->GIni.GILevel = SK_INIT_DATA;
break;
case SK_INIT_IO:
/* Initialization Level 1 */
RetVal = SkGeInit1(pAC, IoC);
if (RetVal != 0) {
break;
}
/* check if the adapter seems to be accessible */
SK_OUT32(IoC, B2_IRQM_INI, SK_TEST_VAL);
SK_IN32(IoC, B2_IRQM_INI, &DWord);
SK_OUT32(IoC, B2_IRQM_INI, 0L);
if (DWord != SK_TEST_VAL) {
RetVal = 2;
break;
}
#ifdef DEBUG
/* check if the number of GIMacsFound matches SK_MAX_MACS */
if (pAC->GIni.GIMacsFound > SK_MAX_MACS) {
RetVal = 1;
break;
}
#endif /* DEBUG */
/* Level 1 successfully passed */
pAC->GIni.GILevel = SK_INIT_IO;
break;
case SK_INIT_RUN:
/* Initialization Level 2 */
if (pAC->GIni.GILevel != SK_INIT_IO) {
#ifndef SK_DIAG
SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E002, SKERR_HWI_E002MSG);
#endif /* !SK_DIAG */
RetVal = 4;
break;
}
SkGeInit2(pAC, IoC);
/* Level 2 successfully passed */
pAC->GIni.GILevel = SK_INIT_RUN;
break;
default:
SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E003, SKERR_HWI_E003MSG);
RetVal = 3;
break;
}
return(RetVal);
} /* SkGeInit */
/******************************************************************************
*
* SkGeDeInit() - Deinitialize the adapter
*
* Description:
* All ports of the adapter will be stopped if not already done.
* Do a software reset and switch off all LEDs.
*
* Returns:
* nothing
*/
void SkGeDeInit(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC) /* I/O Context */
{
int i;
SK_U16 Word;
#ifdef SK_PHY_LP_MODE_DEEP_SLEEP
SK_U16 PmCtlSts;
#endif
#if (!defined(SK_SLIM) && !defined(VCPU))
/* ensure I2C is ready */
SkI2cWaitIrq(pAC, IoC);
#endif
#ifdef SK_PHY_LP_MODE_DEEP_SLEEP
/*
* for power saving purposes within mobile environments
* we set the PHY to coma mode.
*/
#ifdef XXX
if (pAC->GIni.GIVauxAvail) {
/* switch power to VAUX */
SK_OUT8(IoC, B0_POWER_CTRL, (SK_U8)(PC_VAUX_ENA | PC_VCC_ENA |
PC_VAUX_ON | PC_VCC_OFF));
}
#endif /* XXX */
if (CHIP_ID_YUKON_2(pAC) && /* pAC->GIni.GIMacsFound == 1 && */
!pAC->GIni.GIAsfEnabled
#ifdef XXX
|| (pAC->GIni.GIYukonLite && pAC->GIni.GIChipRev >= CHIP_REV_YU_LITE_A3)
#endif /* XXX */
) {
/* flag for SkGmEnterLowPowerMode() that the call was from here */
pAC->GIni.GILevel = SK_INIT_IO;
/* for all ports switch PHY to coma mode */
for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
(void)SkGmEnterLowPowerMode(pAC, IoC, i, PHY_PM_DEEP_SLEEP);
}
}
#else /* !SK_PHY_LP_MODE_DEEP_SLEEP */
if (!pAC->GIni.GIAsfEnabled) {
/* stop all current transfer activity */
for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
if (pAC->GIni.GP[i].PState != SK_PRT_STOP &&
pAC->GIni.GP[i].PState != SK_PRT_RESET) {
SkGeStopPort(pAC, IoC, i, SK_STOP_ALL, SK_HARD_RST);
}
}
}
/* reset all bits in the PCI STATUS register */
/*
* Note: PCI Cfg cycles cannot be used, because they are not
* available on some platforms after 'boot time'.
*/
SK_IN16(IoC, PCI_C(pAC, PCI_STATUS), &Word);
SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
SK_OUT16(IoC, PCI_C(pAC, PCI_STATUS), Word | (SK_U16)PCI_ERRBITS);
SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
if (!pAC->GIni.GIAsfEnabled) {
/* set the SW-reset */
SK_OUT8(IoC, B0_CTST, CS_RST_SET);
}
#endif /* !SK_PHY_LP_MODE_DEEP_SLEEP */
pAC->GIni.GILevel = SK_INIT_DATA;
} /* SkGeDeInit */
/******************************************************************************
*
* SkGeInitPort() Initialize the specified port.
*
* Description:
* PRxQSize, PXSQSize, and PXAQSize has to be
* configured for the specified port before calling this function.
* The descriptor rings has to be initialized too.
*
* o (Re)configure queues of the specified port.
* o configure the MAC of the specified port.
* o put ASIC and MAC(s) in operational mode.
* o initialize Rx/Tx and Sync LED
* o initialize RAM Buffers and MAC FIFOs
*
* The port is ready to connect when returning.
*
* Note:
* The MAC's Rx and Tx state machine is still disabled when returning.
*
* Returns:
* 0: success
* 1: Queue size initialization error. The configured values
* for PRxQSize, PXSQSize, or PXAQSize are invalid for one
* or more queues. The specified port was NOT initialized.
* An error log entry was generated.
* 2: The port has to be stopped before it can be initialized again.
*/
int SkGeInitPort(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC, /* I/O Context */
int Port) /* Port to configure */
{
SK_GEPORT *pPrt;
pPrt = &pAC->GIni.GP[Port];
if (SkGeCheckQSize(pAC, Port) != 0) {
SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E004, SKERR_HWI_E004MSG);
return(1);
}
if (pPrt->PState >= SK_PRT_INIT) {
SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E005, SKERR_HWI_E005MSG);
return(2);
}
/* configuration ok, initialize the Port now */
#ifdef GENESIS
if (pAC->GIni.GIGenesis) {
/* initialize Rx, Tx and Link LED */
/*
* If 1000BT PHY needs LED initialization than swap
* LED and XMAC initialization order
*/
SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_ENA);
SkGeXmitLED(pAC, IoC, MR_ADDR(Port, RX_LED_INI), SK_LED_ENA);
/* The Link LED is initialized by RLMT or Diagnostics itself */
SkXmInitMac(pAC, IoC, Port);
}
#endif /* GENESIS */
#ifdef YUKON
if (pAC->GIni.GIYukon) {
SkGmInitMac(pAC, IoC, Port);
}
#endif /* YUKON */
/* do NOT initialize the Link Sync Counter */
SkGeInitMacFifo(pAC, IoC, Port);
SkGeInitRamBufs(pAC, IoC, Port);
if (pPrt->PXSQSize != 0) {
/* enable Force Sync bit if synchronous queue available */
SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL), TXA_ENA_FSYNC);
}
SkGeInitBmu(pAC, IoC, Port);
/* mark port as initialized */
pPrt->PState = SK_PRT_INIT;
return(0);
} /* SkGeInitPort */
#if (defined(YUK2) && !defined(SK_SLIM))
/******************************************************************************
*
* SkGeRamWrite() - Writes One quadword to RAM
*
* Returns:
* 0
*/
static void SkGeRamWrite(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC, /* I/O Context */
SK_U32 Addr, /* Address to be written to (in quadwords) */
SK_U32 LowDword, /* Lower Dword to be written */
SK_U32 HighDword, /* Upper Dword to be written */
int Port) /* Select RAM buffer (Yukon-2 has 2 RAM buffers) */
{
SK_OUT32(IoC, SELECT_RAM_BUFFER(Port, B3_RAM_ADDR), Addr);
/* Write Access is initiated by writing the upper Dword */
SK_OUT32(IoC, SELECT_RAM_BUFFER(Port, B3_RAM_DATA_LO), LowDword);
SK_OUT32(IoC, SELECT_RAM_BUFFER(Port, B3_RAM_DATA_HI), HighDword);
}
/******************************************************************************
*
* SkYuk2RestartRxBmu() - Restart Receive BMU on Yukon-2
*
* return:
* 0 o.k.
* 1 timeout
*/
int SkYuk2RestartRxBmu(
SK_AC *pAC, /* Adapter Context */
SK_IOC IoC, /* I/O Context */
int Port) /* Port Index (MAC_1 + n) */
{
SK_U16 Word;
SK_U16 MacCtrl;
SK_U16 RxCtrl;
SK_U16 FlushMask;
SK_U16 FlushTrsh;
SK_U32 RamAdr;
SK_U32 StartTime;
SK_U32 CurrTime;
SK_U32 Delta;
SK_U32 TimeOut;
SK_GEPORT *pPrt; /* GIni Port struct pointer */
int Rtv;
SK_U16 WordBuffer[4]; /* Buffer to handle MAC address */
SK_U32 *pH, *pL;
Rtv = 0;
pPrt = &pAC->GIni.GP[Port];
/*
1. save Rx MAC FIFO Flush Mask and Rx MAC FIFO Flush Threshold
2. save GMAC Rx Control Register
3. re-initialize MAC Rx FIFO, Rx RAM Buffer Queue, PCI Rx FIFO,
Rx BMU and Rx Prefetch Unit of the link.
4. set Rx MAC FIFO Flush Mask to 0xffff
set Rx MAC FIFO Flush Threshold to a high value, e.g. 0x20
5. set GMAC to loopback mode and switch GMAC back to Rx/Tx enable
6. clear Rx/Tx Frame Complete IRQ in Rx/T MAC FIFO Control Register
7. send one packet with a size of 64bytes (size below flush threshold)
from TXA RAM Buffer Queue to set the rx_sop flop:
- set TxAQ Write Pointer to (packet size in qwords + 2)
- set TxAQ Level to (packet size in qwords + 2)
- write Internal Status Word 1 and 2 to TxAQ RAM Buffer Queue QWord 0,1
according to figure 61 on page 330 of Yukon-2 Spec.
- write MAC header with Destination Address = own MAC address to
TxAQ RAM Buffer Queue QWords 2 and 3
- set TxAQ Packet Counter to 1 -> packet is transmitted immediately
8. poll GMAC IRQ Source Register for IRQ Rx/Tx Frame Complete
9. restore GMAC Rx Control Register
10. restore Rx MAC FIFO Flush Mask and Rx MAC FIFO Flush Threshold
11. set GMAC back to GMII mode
*/
/* save Rx GMAC FIFO Flush Mask */
SK_IN16(IoC, MR_ADDR(Port, RX_GMF_FL_MSK), &FlushMask);
/* save Rx GMAC FIFO Flush Threshold */
SK_IN16(IoC, MR_ADDR(Port, RX_GMF_FL_THR), &FlushTrsh);
/* save GMAC Rx Control Register */
GM_IN16(IoC, Port, GM_RX_CTRL, &RxCtrl);
/* configure the GMAC FIFOs */
SkGeInitMacFifo(pAC, IoC, Port);
SkGeInitRamBufs(pAC, IoC, Port);
SkGeInitBmu(pAC, IoC, Port);
/* configure Rx GMAC FIFO */
SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), GMF_RX_CTRL_DEF);
/* set Rx GMAC FIFO Flush Mask */
SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_FL_MSK), 0xffff);
/* set Rx GMAC FIFO Flush Threshold */
SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_FL_THR), 0x20);
/* set to promiscuous mode */
Word = RxCtrl & ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
/* set GMAC Rx Control Register */
GM_OUT16(IoC, Port, GM_RX_CTRL, Word);
/* get General Purpose Control */
GM_IN16(IoC, Port, GM_GP_CTRL, &MacCtrl);
/* enable MAC Loopback Mode*/
GM_OUT16(IoC, Port, GM_GP_CTRL, MacCtrl | GM_GPCR_LOOP_ENA);
/* enable MAC Loopback Mode and Rx/Tx */
GM_OUT16(IoC, Port, GM_GP_CTRL, MacCtrl | GM_GPCR_LOOP_ENA |
GM_GPCR_RX_ENA | GM_GPCR_TX_ENA);
/* clear GMAC IRQ Rx Frame Complete */
SK_OUT8(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), (SK_U8)GMF_CLI_RX_FC);
/* clear GMAC IRQ Tx Frame Complete */
SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)GMF_CLI_TX_FC);
/* send one packet with a size of 64bytes from RAM buffer*/
RamAdr = pPrt->PXaQRamStart / 8;
SK_OUT32(IoC, RB_ADDR(pPrt->PXaQOff, RB_WP), RamAdr + 10);
SK_OUT32(IoC, RB_ADDR(pPrt->PXaQOff, RB_LEV), 10);
/* write 1st status quad word (packet end address in RAM, packet length */
SkGeRamWrite(pAC, IoC, RamAdr, (RamAdr + 9) << 16, 64, Port);
/* write 2nd status quad word */
SkGeRamWrite(pAC, IoC, RamAdr + 1, 0, 0, Port);
WordBuffer[0] = pPrt->PMacAddr[0];
WordBuffer[1] = pPrt->PMacAddr[1];
WordBuffer[2] = pPrt->PMacAddr[2];
WordBuffer[3] = pPrt->PMacAddr[0];
/* write DA to MAC header */
pL =(SK_U32 *)WordBuffer;
pH = pL++;
SkGeRamWrite(pAC, IoC, (RamAdr + 2), (SK_U32)*pL, (SK_U32)*pH, Port);
WordBuffer[0] = pPrt->PMacAddr[1];
WordBuffer[1] = pPrt->PMacAddr[2];
WordBuffer[2] = 0x3200; /* len / type field (big endian) */
WordBuffer[3] = 0x00;
SkGeRamWrite(pAC, IoC, RamAdr + 3, *pL, *pH, Port);
SkGeRamWrite(pAC, IoC, RamAdr + 4, 0x4c56524d, /* "MRVL" */
0x00464d2d, Port); /* "-MF" */
SkGeRamWrite(pAC, IoC, RamAdr + 5, 0x00000000, 0x00000000, Port);
SkGeRamWrite(pAC, IoC, RamAdr + 6, 0x00000000, 0x00000000, Port);
SkGeRamWrite(pAC, IoC, RamAdr + 7, 0x00000000, 0x00000000, Port);
SkGeRamWrite(pAC, IoC, RamAdr + 8, 0x00000000, 0x00000000, Port);
SkGeRamWrite(pAC, IoC, RamAdr + 9, 0x00000000, 0x00000000, Port);
SK_OUT32(IoC, RB_ADDR(pPrt->PXaQOff, RB_PC), 1);
SK_IN32(IoC, GMAC_TI_ST_VAL, &StartTime);
/* set timeout to 10 ms */
TimeOut = HW_MS_TO_TICKS(pAC, 10);
do {
SK_IN32(IoC, GMAC_TI_ST_VAL, &CurrTime);
if (CurrTime >= StartTime) {
Delta = CurrTime - StartTime;
}
else {
Delta = CurrTime + ~StartTime + 1;
}
if (Delta > TimeOut) {
Rtv = 1;
break;
}
/* read the GMAC Interrupt source register */
SK_IN16(IoC, MR_ADDR(Port, GMAC_IRQ_SRC), &Word);
} while ((Word & (GM_IS_TX_COMPL | GM_IS_RX_COMPL)) !=
(GM_IS_TX_COMPL | GM_IS_RX_COMPL));
/* disable MAC Loopback Mode and Rx/Tx */
GM_OUT16(IoC, Port, GM_GP_CTRL, MacCtrl);
/* restore GMAC Rx Control Register */
GM_OUT16(IoC, Port, GM_RX_CTRL, RxCtrl);
/* restore Rx GMAC FIFO Flush Mask */
SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_FL_MSK), FlushMask);
/* restore Rx GMAC FIFO Flush Threshold */
SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_FL_THR), FlushTrsh);
return(Rtv);
} /* SkYuk2RestartRxBmu */
#endif /* YUK2 && !SK_SLIM */
#endif