blob: 77e9246a53ef2f969e93996ff67c4dc3b8db67ed [file] [log] [blame]
/******************************************************************************
*
* Name: skethtool.c
* Project: GEnesis, PCI Gigabit Ethernet Adapter
* Version: $Revision: 1.3.2.11 $
* Date: $Date: 2005/10/27 12:42:34 $
* Purpose: All functions regarding ethtool handling
*
******************************************************************************/
/******************************************************************************
*
* (C)Copyright 1998-2002 SysKonnect GmbH.
* (C)Copyright 2002-2005 Marvell.
*
* Driver for Marvell Yukon/2 chipset and SysKonnect Gigabit Ethernet
* Server Adapters.
*
* Author: Ralph Roesler (rroesler@syskonnect.de)
* Mirko Lindner (mlindner@syskonnect.de)
*
* Address all question to: linux@syskonnect.de
*
* 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.
*
*****************************************************************************/
#include <config.h>
#ifdef CONFIG_SK98
#include "h/skdrv1st.h"
#include "h/skdrv2nd.h"
#include "h/skversion.h"
#if 0 /* uboot */
#include <linux/ethtool.h>
#include <linux/module.h>
#include <linux/timer.h>
#endif
/******************************************************************************
*
* External Functions and Data
*
*****************************************************************************/
extern void SkDimDisableModeration(SK_AC *pAC, int CurrentModeration);
extern void SkDimEnableModerationIfNeeded(SK_AC *pAC);
/******************************************************************************
*
* Defines
*
*****************************************************************************/
#ifndef ETHT_STATSTRING_LEN
#define ETHT_STATSTRING_LEN 32
#endif
#define SK98LIN_STAT(m) sizeof(((SK_AC *)0)->m),offsetof(SK_AC, m)
#define SUPP_COPPER_ALL (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
SUPPORTED_1000baseT_Half| SUPPORTED_1000baseT_Full| \
SUPPORTED_TP)
#define ADV_COPPER_ALL (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
ADVERTISED_1000baseT_Half| ADVERTISED_1000baseT_Full| \
ADVERTISED_TP)
#define SUPP_FIBRE_ALL (SUPPORTED_1000baseT_Full | \
SUPPORTED_FIBRE | \
SUPPORTED_Autoneg)
#define ADV_FIBRE_ALL (ADVERTISED_1000baseT_Full | \
ADVERTISED_FIBRE | \
ADVERTISED_Autoneg)
/******************************************************************************
*
* Local Function Prototypes
*
*****************************************************************************/
#ifdef ETHTOOL_GSET
static void getSettings(SK_AC *pAC, int port, struct ethtool_cmd *ecmd);
#endif
#ifdef ETHTOOL_SSET
static int setSettings(SK_AC *pAC, int port, struct ethtool_cmd *ecmd);
#endif
#ifdef ETHTOOL_GPAUSEPARAM
static void getPauseParams(SK_AC *pAC, int port, struct ethtool_pauseparam *epause);
#endif
#ifdef ETHTOOL_SPAUSEPARAM
static int setPauseParams(SK_AC *pAC, int port, struct ethtool_pauseparam *epause);
#endif
#ifdef ETHTOOL_GDRVINFO
static void getDriverInfo(SK_AC *pAC, int port, struct ethtool_drvinfo *edrvinfo);
#endif
#ifdef ETHTOOL_PHYS_ID
static int startLocateNIC(SK_AC *pAC, int port, struct ethtool_value *blinkSecs);
static void toggleLeds(unsigned long ptr);
#endif
#ifdef ETHTOOL_GCOALESCE
static void getModerationParams(SK_AC *pAC, int port, struct ethtool_coalesce *ecoalesc);
#endif
#ifdef ETHTOOL_SCOALESCE
static int setModerationParams(SK_AC *pAC, int port, struct ethtool_coalesce *ecoalesc);
#endif
#ifdef ETHTOOL_GWOL
static void getWOLsettings(SK_AC *pAC, int port, struct ethtool_wolinfo *ewol);
#endif
#ifdef ETHTOOL_SWOL
static int setWOLsettings(SK_AC *pAC, int port, struct ethtool_wolinfo *ewol);
#endif
static int getPortNumber(struct net_device *netdev, struct ifreq *ifr);
/******************************************************************************
*
* Local Variables
*
*****************************************************************************/
struct sk98lin_stats {
char stat_string[ETHT_STATSTRING_LEN];
int sizeof_stat;
int stat_offset;
};
static struct sk98lin_stats sk98lin_etht_stats_port0[] = {
{ "rx_packets" , SK98LIN_STAT(PnmiStruct.Stat[0].StatRxOkCts) },
{ "tx_packets" , SK98LIN_STAT(PnmiStruct.Stat[0].StatTxOkCts) },
{ "rx_bytes" , SK98LIN_STAT(PnmiStruct.Stat[0].StatRxOctetsOkCts) },
{ "tx_bytes" , SK98LIN_STAT(PnmiStruct.Stat[0].StatTxOctetsOkCts) },
{ "rx_errors" , SK98LIN_STAT(PnmiStruct.InErrorsCts) },
{ "tx_errors" , SK98LIN_STAT(PnmiStruct.Stat[0].StatTxSingleCollisionCts) },
{ "rx_dropped" , SK98LIN_STAT(PnmiStruct.RxNoBufCts) },
{ "tx_dropped" , SK98LIN_STAT(PnmiStruct.TxNoBufCts) },
{ "multicasts" , SK98LIN_STAT(PnmiStruct.Stat[0].StatRxMulticastOkCts) },
{ "collisions" , SK98LIN_STAT(PnmiStruct.Stat[0].StatTxSingleCollisionCts) },
{ "rx_length_errors" , SK98LIN_STAT(PnmiStruct.Stat[0].StatRxRuntCts) },
{ "rx_buffer_overflow_errors" , SK98LIN_STAT(PnmiStruct.Stat[0].StatRxFifoOverflowCts) },
{ "rx_crc_errors" , SK98LIN_STAT(PnmiStruct.Stat[0].StatRxFcsCts) },
{ "rx_frame_errors" , SK98LIN_STAT(PnmiStruct.Stat[0].StatRxFramingCts) },
{ "rx_too_short_errors" , SK98LIN_STAT(PnmiStruct.Stat[0].StatRxShortsCts) },
{ "rx_too_long_errors" , SK98LIN_STAT(PnmiStruct.Stat[0].StatRxTooLongCts) },
{ "rx_carrier_extension_errors", SK98LIN_STAT(PnmiStruct.Stat[0].StatRxCextCts) },
{ "rx_symbol_errors" , SK98LIN_STAT(PnmiStruct.Stat[0].StatRxSymbolCts) },
{ "rx_llc_mac_size_errors" , SK98LIN_STAT(PnmiStruct.Stat[0].StatRxIRLengthCts) },
{ "rx_carrier_errors" , SK98LIN_STAT(PnmiStruct.Stat[0].StatRxCarrierCts) },
{ "rx_jabber_errors" , SK98LIN_STAT(PnmiStruct.Stat[0].StatRxJabberCts) },
{ "rx_missed_errors" , SK98LIN_STAT(PnmiStruct.Stat[0].StatRxMissedCts) },
{ "tx_abort_collision_errors" , SK98LIN_STAT(stats.tx_aborted_errors) },
{ "tx_carrier_errors" , SK98LIN_STAT(PnmiStruct.Stat[0].StatTxCarrierCts) },
{ "tx_buffer_underrun_errors" , SK98LIN_STAT(PnmiStruct.Stat[0].StatTxFifoUnderrunCts) },
{ "tx_heartbeat_errors" , SK98LIN_STAT(PnmiStruct.Stat[0].StatTxCarrierCts) } ,
{ "tx_window_errors" , SK98LIN_STAT(stats.tx_window_errors) }
};
static struct sk98lin_stats sk98lin_etht_stats_port1[] = {
{ "rx_packets" , SK98LIN_STAT(PnmiStruct.Stat[1].StatRxOkCts) },
{ "tx_packets" , SK98LIN_STAT(PnmiStruct.Stat[1].StatTxOkCts) },
{ "rx_bytes" , SK98LIN_STAT(PnmiStruct.Stat[1].StatRxOctetsOkCts) },
{ "tx_bytes" , SK98LIN_STAT(PnmiStruct.Stat[1].StatTxOctetsOkCts) },
{ "rx_errors" , SK98LIN_STAT(PnmiStruct.InErrorsCts) },
{ "tx_errors" , SK98LIN_STAT(PnmiStruct.Stat[1].StatTxSingleCollisionCts) },
{ "rx_dropped" , SK98LIN_STAT(PnmiStruct.RxNoBufCts) },
{ "tx_dropped" , SK98LIN_STAT(PnmiStruct.TxNoBufCts) },
{ "multicasts" , SK98LIN_STAT(PnmiStruct.Stat[1].StatRxMulticastOkCts) },
{ "collisions" , SK98LIN_STAT(PnmiStruct.Stat[1].StatTxSingleCollisionCts) },
{ "rx_length_errors" , SK98LIN_STAT(PnmiStruct.Stat[1].StatRxRuntCts) },
{ "rx_buffer_overflow_errors" , SK98LIN_STAT(PnmiStruct.Stat[1].StatRxFifoOverflowCts) },
{ "rx_crc_errors" , SK98LIN_STAT(PnmiStruct.Stat[1].StatRxFcsCts) },
{ "rx_frame_errors" , SK98LIN_STAT(PnmiStruct.Stat[1].StatRxFramingCts) },
{ "rx_too_short_errors" , SK98LIN_STAT(PnmiStruct.Stat[1].StatRxShortsCts) },
{ "rx_too_long_errors" , SK98LIN_STAT(PnmiStruct.Stat[1].StatRxTooLongCts) },
{ "rx_carrier_extension_errors", SK98LIN_STAT(PnmiStruct.Stat[1].StatRxCextCts) },
{ "rx_symbol_errors" , SK98LIN_STAT(PnmiStruct.Stat[1].StatRxSymbolCts) },
{ "rx_llc_mac_size_errors" , SK98LIN_STAT(PnmiStruct.Stat[1].StatRxIRLengthCts) },
{ "rx_carrier_errors" , SK98LIN_STAT(PnmiStruct.Stat[1].StatRxCarrierCts) },
{ "rx_jabber_errors" , SK98LIN_STAT(PnmiStruct.Stat[1].StatRxJabberCts) },
{ "rx_missed_errors" , SK98LIN_STAT(PnmiStruct.Stat[1].StatRxMissedCts) },
{ "tx_abort_collision_errors" , SK98LIN_STAT(stats.tx_aborted_errors) },
{ "tx_carrier_errors" , SK98LIN_STAT(PnmiStruct.Stat[1].StatTxCarrierCts) },
{ "tx_buffer_underrun_errors" , SK98LIN_STAT(PnmiStruct.Stat[1].StatTxFifoUnderrunCts) },
{ "tx_heartbeat_errors" , SK98LIN_STAT(PnmiStruct.Stat[1].StatTxCarrierCts) } ,
{ "tx_window_errors" , SK98LIN_STAT(stats.tx_window_errors) }
};
#define SK98LIN_STATS_LEN sizeof(sk98lin_etht_stats_port0) / sizeof(struct sk98lin_stats)
static int nbrBlinkQuarterSeconds;
static int currentPortIndex;
static SK_BOOL isLocateNICrunning = SK_FALSE;
static SK_BOOL isDualNetCard = SK_FALSE;
static SK_BOOL doSwitchLEDsOn = SK_FALSE;
static SK_BOOL boardWasDown[2] = { SK_FALSE, SK_FALSE };
static struct timer_list locateNICtimer;
/******************************************************************************
*
* Global Functions
*
*****************************************************************************/
/*****************************************************************************
*
* SkEthIoctl - IOCTL entry point for all ethtool queries
*
* Description:
* Any IOCTL request that has to deal with the ethtool command tool is
* dispatched via this function.
*
* Returns:
* ==0: everything fine, no error
* !=0: the return value is the error code of the failure
*/
int SkEthIoctl(
struct net_device *netdev, /* the pointer to netdev structure */
struct ifreq *ifr) /* what interface the request refers to? */
{
DEV_NET *pNet = (DEV_NET*) netdev->priv;
SK_AC *pAC = pNet->pAC;
void *pAddr = ifr->ifr_data;
int port = getPortNumber(netdev, ifr);
SK_PNMI_STRUCT_DATA *pPnmiStruct = &pAC->PnmiStruct;
SK_U32 Size = sizeof(SK_PNMI_STRUCT_DATA);
SK_U32 cmd;
struct sk98lin_stats *sk98lin_etht_stats =
(port == 0) ? sk98lin_etht_stats_port0 : sk98lin_etht_stats_port1;
if (get_user(cmd, (uint32_t *) pAddr)) {
return -EFAULT;
}
switch(cmd) {
#ifdef ETHTOOL_GSET
case ETHTOOL_GSET: {
struct ethtool_cmd ecmd = { ETHTOOL_GSET };
getSettings(pAC, port, &ecmd);
if(copy_to_user(pAddr, &ecmd, sizeof(ecmd))) {
return -EFAULT;
}
return 0;
}
break;
#endif
#ifdef ETHTOOL_SSET
case ETHTOOL_SSET: {
struct ethtool_cmd ecmd;
if(copy_from_user(&ecmd, pAddr, sizeof(ecmd))) {
return -EFAULT;
}
return setSettings(pAC, port, &ecmd);
}
break;
#endif
#ifdef ETHTOOL_GLINK
case ETHTOOL_GLINK: {
struct ethtool_value edata = { ETHTOOL_GLINK };
edata.data = netif_carrier_ok(netdev);
if (copy_to_user(pAddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
#endif
#ifdef ETHTOOL_GDRVINFO
case ETHTOOL_GDRVINFO: {
struct ethtool_drvinfo drvinfo = { ETHTOOL_GDRVINFO };
getDriverInfo(pAC, port, &drvinfo);
if(copy_to_user(pAddr, &drvinfo, sizeof(drvinfo))) {
return -EFAULT;
}
return 0;
}
break;
#endif
#ifdef ETHTOOL_GSTRINGS
case ETHTOOL_GSTRINGS: {
struct ethtool_gstrings gstrings = { ETHTOOL_GSTRINGS };
char *strings = NULL;
int err = 0;
if(copy_from_user(&gstrings, pAddr, sizeof(gstrings))) {
return -EFAULT;
}
switch(gstrings.string_set) {
#ifdef ETHTOOL_GSTATS
case ETH_SS_STATS: {
int i;
gstrings.len = SK98LIN_STATS_LEN;
if ((strings = kmalloc(SK98LIN_STATS_LEN*ETHT_STATSTRING_LEN,GFP_KERNEL)) == NULL) {
return -ENOMEM;
}
for(i=0; i < SK98LIN_STATS_LEN; i++) {
memcpy(&strings[i * ETHT_STATSTRING_LEN],
&(sk98lin_etht_stats[i].stat_string),
ETHT_STATSTRING_LEN);
}
}
break;
#endif
default:
return -EOPNOTSUPP;
}
if(copy_to_user(pAddr, &gstrings, sizeof(gstrings))) {
err = -EFAULT;
}
pAddr = (void *) ((unsigned long int) pAddr + offsetof(struct ethtool_gstrings, data));
if(!err && copy_to_user(pAddr, strings, gstrings.len * ETH_GSTRING_LEN)) {
err = -EFAULT;
}
kfree(strings);
return err;
}
#endif
#ifdef ETHTOOL_GSTATS
case ETHTOOL_GSTATS: {
struct {
struct ethtool_stats eth_stats;
uint64_t data[SK98LIN_STATS_LEN];
} stats = { {ETHTOOL_GSTATS, SK98LIN_STATS_LEN} };
int i;
if (netif_running(pAC->dev[port])) {
SkPnmiGetStruct(pAC, pAC->IoBase, pPnmiStruct, &Size, port);
}
for(i = 0; i < SK98LIN_STATS_LEN; i++) {
if (netif_running(pAC->dev[port])) {
stats.data[i] = (sk98lin_etht_stats[i].sizeof_stat ==
sizeof(uint64_t)) ?
*(uint64_t *)((char *)pAC +
sk98lin_etht_stats[i].stat_offset) :
*(uint32_t *)((char *)pAC +
sk98lin_etht_stats[i].stat_offset);
} else {
stats.data[i] = (sk98lin_etht_stats[i].sizeof_stat ==
sizeof(uint64_t)) ? (uint64_t) 0 : (uint32_t) 0;
}
}
if(copy_to_user(pAddr, &stats, sizeof(stats))) {
return -EFAULT;
}
return 0;
}
#endif
#ifdef ETHTOOL_PHYS_ID
case ETHTOOL_PHYS_ID: {
struct ethtool_value blinkSecs;
if(copy_from_user(&blinkSecs, pAddr, sizeof(blinkSecs))) {
return -EFAULT;
}
return startLocateNIC(pAC, port, &blinkSecs);
}
#endif
#ifdef ETHTOOL_GPAUSEPARAM
case ETHTOOL_GPAUSEPARAM: {
struct ethtool_pauseparam epause = { ETHTOOL_GPAUSEPARAM };
getPauseParams(pAC, port, &epause);
if(copy_to_user(pAddr, &epause, sizeof(epause))) {
return -EFAULT;
}
return 0;
}
#endif
#ifdef ETHTOOL_SPAUSEPARAM
case ETHTOOL_SPAUSEPARAM: {
struct ethtool_pauseparam epause;
if(copy_from_user(&epause, pAddr, sizeof(epause))) {
return -EFAULT;
}
return setPauseParams(pAC, port, &epause);
}
#endif
#ifdef ETHTOOL_GSG
case ETHTOOL_GSG: {
struct ethtool_value edata = { ETHTOOL_GSG };
edata.data = (netdev->features & NETIF_F_SG) != 0;
if (copy_to_user(pAddr, &edata, sizeof(edata))) {
return -EFAULT;
}
return 0;
}
#endif
#ifdef ETHTOOL_SSG
case ETHTOOL_SSG: {
struct ethtool_value edata;
if (copy_from_user(&edata, pAddr, sizeof(edata))) {
return -EFAULT;
}
if (pAC->ChipsetType) { /* Don't handle if Genesis */
if (edata.data) {
netdev->features |= NETIF_F_SG;
} else {
netdev->features &= ~NETIF_F_SG;
}
}
return 0;
}
#endif
#ifdef ETHTOOL_GRXCSUM
case ETHTOOL_GRXCSUM: {
struct ethtool_value edata = { ETHTOOL_GRXCSUM };
edata.data = pAC->RxPort[port].UseRxCsum;
if (copy_to_user(pAddr, &edata, sizeof(edata))) {
return -EFAULT;
}
return 0;
}
#endif
#ifdef ETHTOOL_SRXCSUM
case ETHTOOL_SRXCSUM: {
struct ethtool_value edata;
if (copy_from_user(&edata, pAddr, sizeof(edata))) {
return -EFAULT;
}
pAC->RxPort[port].UseRxCsum = edata.data;
return 0;
}
#endif
#ifdef ETHTOOL_GTXCSUM
case ETHTOOL_GTXCSUM: {
struct ethtool_value edata = { ETHTOOL_GTXCSUM };
edata.data = ((netdev->features & NETIF_F_IP_CSUM) != 0);
if (copy_to_user(pAddr, &edata, sizeof(edata))) {
return -EFAULT;
}
return 0;
}
#endif
#ifdef ETHTOOL_STXCSUM
case ETHTOOL_STXCSUM: {
struct ethtool_value edata;
if (copy_from_user(&edata, pAddr, sizeof(edata))) {
return -EFAULT;
}
if (pAC->ChipsetType) { /* Don't handle if Genesis */
if (edata.data) {
netdev->features |= NETIF_F_IP_CSUM;
} else {
netdev->features &= ~NETIF_F_IP_CSUM;
}
}
return 0;
}
#endif
#ifdef ETHTOOL_NWAY_RST
case ETHTOOL_NWAY_RST: {
if(netif_running(netdev)) {
(*netdev->stop)(netdev);
(*netdev->open)(netdev);
}
return 0;
}
#endif
#ifdef NETIF_F_TSO
#ifdef ETHTOOL_GTSO
case ETHTOOL_GTSO: {
struct ethtool_value edata = { ETHTOOL_GTSO };
edata.data = (netdev->features & NETIF_F_TSO) != 0;
if (copy_to_user(pAddr, &edata, sizeof(edata))) {
return -EFAULT;
}
return 0;
}
#endif
#ifdef ETHTOOL_STSO
case ETHTOOL_STSO: {
struct ethtool_value edata;
if (CHIP_ID_YUKON_2(pAC)) {
if (copy_from_user(&edata, pAddr, sizeof(edata))) {
return -EFAULT;
}
if (edata.data) {
netdev->features |= NETIF_F_TSO;
} else {
netdev->features &= ~NETIF_F_TSO;
}
return 0;
}
return -EOPNOTSUPP;
}
#endif
#endif
#ifdef ETHTOOL_GCOALESCE
case ETHTOOL_GCOALESCE: {
struct ethtool_coalesce ecoalesc = { ETHTOOL_GCOALESCE };
getModerationParams(pAC, port, &ecoalesc);
if(copy_to_user(pAddr, &ecoalesc, sizeof(ecoalesc))) {
return -EFAULT;
}
return 0;
}
#endif
#ifdef ETHTOOL_SCOALESCE
case ETHTOOL_SCOALESCE: {
struct ethtool_coalesce ecoalesc;
if(copy_from_user(&ecoalesc, pAddr, sizeof(ecoalesc))) {
return -EFAULT;
}
return setModerationParams(pAC, port, &ecoalesc);
}
#endif
#ifdef ETHTOOL_GWOL
case ETHTOOL_GWOL: {
struct ethtool_wolinfo ewol = { ETHTOOL_GWOL };
getWOLsettings(pAC, port, &ewol);
if(copy_to_user(pAddr, &ewol, sizeof(ewol))) {
return -EFAULT;
}
return 0;
}
#endif
#ifdef ETHTOOL_SWOL
case ETHTOOL_SWOL: {
struct ethtool_wolinfo ewol;
if(copy_from_user(&ewol, pAddr, sizeof(ewol))) {
return -EFAULT;
}
return setWOLsettings(pAC, port, &ewol);
}
#endif
default:
return -EOPNOTSUPP;
}
} /* SkEthIoctl() */
/******************************************************************************
*
* Local Functions
*
*****************************************************************************/
#ifdef ETHTOOL_GSET
/*****************************************************************************
*
* getSettings - retrieves the current settings of the selected adapter
*
* Description:
* The current configuration of the selected adapter is returned.
* This configuration involves a)speed, b)duplex and c)autoneg plus
* a number of other variables.
*
* Returns: N/A
*
*/
static void getSettings(
SK_AC *pAC, /* pointer to adapter control context */
int port, /* the port of the selected adapter */
struct ethtool_cmd *ecmd) /* mandatory command structure for results */
{
SK_GEPORT *pPort = &pAC->GIni.GP[port];
static int DuplexAutoNegConfMap[9][3]= {
{ -1 , -1 , -1 },
{ 0 , -1 , -1 },
{ SK_LMODE_HALF , DUPLEX_HALF, AUTONEG_DISABLE },
{ SK_LMODE_FULL , DUPLEX_FULL, AUTONEG_DISABLE },
{ SK_LMODE_AUTOHALF , DUPLEX_HALF, AUTONEG_ENABLE },
{ SK_LMODE_AUTOFULL , DUPLEX_FULL, AUTONEG_ENABLE },
{ SK_LMODE_AUTOBOTH , DUPLEX_FULL, AUTONEG_ENABLE },
{ SK_LMODE_AUTOSENSE , -1 , -1 },
{ SK_LMODE_INDETERMINATED, -1 , -1 }
};
static int SpeedConfMap[6][2] = {
{ 0 , -1 },
{ SK_LSPEED_AUTO , -1 },
{ SK_LSPEED_10MBPS , SPEED_10 },
{ SK_LSPEED_100MBPS , SPEED_100 },
{ SK_LSPEED_1000MBPS , SPEED_1000 },
{ SK_LSPEED_INDETERMINATED, -1 }
};
static int AdvSpeedMap[6][2] = {
{ 0 , -1 },
{ SK_LSPEED_AUTO , -1 },
{ SK_LSPEED_10MBPS , ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full },
{ SK_LSPEED_100MBPS , ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full },
{ SK_LSPEED_1000MBPS , ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full},
{ SK_LSPEED_INDETERMINATED, -1 }
};
ecmd->phy_address = port;
ecmd->speed = SpeedConfMap[pPort->PLinkSpeedUsed][1];
ecmd->duplex = DuplexAutoNegConfMap[pPort->PLinkModeStatus][1];
ecmd->autoneg = DuplexAutoNegConfMap[pPort->PLinkModeStatus][2];
ecmd->transceiver = XCVR_INTERNAL;
if (pAC->GIni.GICopperType) {
ecmd->port = PORT_TP;
ecmd->supported = (SUPP_COPPER_ALL|SUPPORTED_Autoneg);
if (pAC->GIni.GIGenesis) {
ecmd->supported &= ~(SUPPORTED_10baseT_Half);
ecmd->supported &= ~(SUPPORTED_10baseT_Full);
ecmd->supported &= ~(SUPPORTED_100baseT_Half);
ecmd->supported &= ~(SUPPORTED_100baseT_Full);
} else {
if (pAC->GIni.GIChipId == CHIP_ID_YUKON) {
ecmd->supported &= ~(SUPPORTED_1000baseT_Half);
}
if (pAC->GIni.GIChipId == CHIP_ID_YUKON_FE) {
ecmd->supported &= ~(SUPPORTED_1000baseT_Half);
ecmd->supported &= ~(SUPPORTED_1000baseT_Full);
}
}
if (pAC->GIni.GP[0].PLinkSpeed != SK_LSPEED_AUTO) {
ecmd->advertising = AdvSpeedMap[pPort->PLinkSpeed][1];
if (pAC->GIni.GIChipId == CHIP_ID_YUKON) {
ecmd->advertising &= ~(SUPPORTED_1000baseT_Half);
}
} else {
ecmd->advertising = ecmd->supported;
}
if (ecmd->autoneg == AUTONEG_ENABLE) {
ecmd->advertising |= ADVERTISED_Autoneg;
} else {
ecmd->advertising = ADVERTISED_TP;
}
} else {
ecmd->port = PORT_FIBRE;
ecmd->supported = (SUPP_FIBRE_ALL);
ecmd->advertising = (ADV_FIBRE_ALL);
}
}
#endif
#ifdef ETHTOOL_SSET
/*****************************************************************************
*
* setSettings - configures the settings of a selected adapter
*
* Description:
* Possible settings that may be altered are a)speed, b)duplex or
* c)autonegotiation.
*
* Returns:
* ==0: everything fine, no error
* !=0: the return value is the error code of the failure
*/
static int setSettings(
SK_AC *pAC, /* pointer to adapter control context */
int port, /* the port of the selected adapter */
struct ethtool_cmd *ecmd) /* command structure containing settings */
{
DEV_NET *pNet = (DEV_NET *) pAC->dev[port]->priv;
SK_U32 Instance;
char Buf[4];
unsigned int Len = 1;
int Ret;
if (port == 0) {
Instance = (pAC->RlmtNets == 2) ? 1 : 2;
} else {
Instance = (pAC->RlmtNets == 2) ? 2 : 3;
}
if (((ecmd->autoneg == AUTONEG_DISABLE) || (ecmd->autoneg == AUTONEG_ENABLE)) &&
((ecmd->duplex == DUPLEX_FULL) || (ecmd->duplex == DUPLEX_HALF))) {
if (ecmd->autoneg == AUTONEG_DISABLE) {
if (ecmd->duplex == DUPLEX_FULL) {
*Buf = (char) SK_LMODE_FULL;
} else {
*Buf = (char) SK_LMODE_HALF;
}
} else {
if (ecmd->duplex == DUPLEX_FULL) {
*Buf = (char) SK_LMODE_AUTOFULL;
} else {
*Buf = (char) SK_LMODE_AUTOHALF;
}
}
Ret = SkPnmiSetVar(pAC, pAC->IoBase, OID_SKGE_LINK_MODE,
&Buf, &Len, Instance, pNet->NetNr);
if (Ret != SK_PNMI_ERR_OK) {
return -EINVAL;
}
} else if (ecmd->autoneg == AUTONEG_ENABLE) {
/* Set default values */
*Buf = (char) SK_LMODE_AUTOFULL;
Ret = SkPnmiSetVar(pAC, pAC->IoBase, OID_SKGE_LINK_MODE,
&Buf, &Len, Instance, pNet->NetNr);
}
if ((ecmd->speed == SPEED_1000) ||
(ecmd->speed == SPEED_100) ||
(ecmd->speed == SPEED_10)) {
if (ecmd->autoneg == AUTONEG_ENABLE) {
*Buf = (char) SK_LSPEED_AUTO;
} else if (ecmd->speed == SPEED_1000) {
*Buf = (char) SK_LSPEED_1000MBPS;
} else if (ecmd->speed == SPEED_100) {
*Buf = (char) SK_LSPEED_100MBPS;
} else {
*Buf = (char) SK_LSPEED_10MBPS;
}
Ret = SkPnmiSetVar(pAC, pAC->IoBase, OID_SKGE_SPEED_MODE,
&Buf, &Len, Instance, pNet->NetNr);
if (Ret != SK_PNMI_ERR_OK) {
return -EINVAL;
}
} else if (ecmd->autoneg == AUTONEG_ENABLE) {
*Buf = (char) SK_LSPEED_AUTO;
Ret = SkPnmiSetVar(pAC, pAC->IoBase, OID_SKGE_SPEED_MODE,
&Buf, &Len, Instance, pNet->NetNr);
} else {
return -EINVAL;
}
return 0;
}
#endif
#ifdef ETHTOOL_GPAUSEPARAM
/*****************************************************************************
*
* getPauseParams - retrieves the pause parameters
*
* Description:
* All current pause parameters of a selected adapter are placed
* in the passed ethtool_pauseparam structure and are returned.
*
* Returns: N/A
*
*/
static void getPauseParams(
SK_AC *pAC, /* pointer to adapter control context */
int port, /* the port of the selected adapter */
struct ethtool_pauseparam *epause) /* pause parameter struct for result */
{
SK_GEPORT *pPort = &pAC->GIni.GP[port];
epause->rx_pause = 0;
epause->tx_pause = 0;
if (pPort->PFlowCtrlMode == SK_FLOW_MODE_LOC_SEND) {
epause->tx_pause = 1;
}
if ((pPort->PFlowCtrlMode == SK_FLOW_MODE_SYMMETRIC) ||
(pPort->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM)) {
epause->tx_pause = 1;
epause->rx_pause = 1;
}
if ((epause->rx_pause == 0) && (epause->tx_pause == 0)) {
epause->autoneg = SK_FALSE;
} else {
epause->autoneg = SK_TRUE;
}
}
#endif
#ifdef ETHTOOL_SPAUSEPARAM
/*****************************************************************************
*
* setPauseParams - configures the pause parameters of an adapter
*
* Description:
* This function sets the Rx or Tx pause parameters
*
* Returns:
* ==0: everything fine, no error
* !=0: the return value is the error code of the failure
*/
static int setPauseParams(
SK_AC *pAC, /* pointer to adapter control context */
int port, /* the port of the selected adapter */
struct ethtool_pauseparam *epause) /* pause parameter struct with params */
{
SK_GEPORT *pPort = &pAC->GIni.GP[port];
DEV_NET *pNet = (DEV_NET *) pAC->dev[port]->priv;
int PrevSpeedVal = pPort->PLinkSpeedUsed;
SK_U32 Instance;
char Buf[4];
int Ret;
SK_BOOL prevAutonegValue = SK_TRUE;
int prevTxPause = 0;
int prevRxPause = 0;
unsigned int Len = 1;
if (port == 0) {
Instance = (pAC->RlmtNets == 2) ? 1 : 2;
} else {
Instance = (pAC->RlmtNets == 2) ? 2 : 3;
}
/*
** we have to determine the current settings to see if
** the operator requested any modification of the flow
** control parameters...
*/
if (pPort->PFlowCtrlMode == SK_FLOW_MODE_LOC_SEND) {
prevTxPause = 1;
}
if ((pPort->PFlowCtrlMode == SK_FLOW_MODE_SYMMETRIC) ||
(pPort->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM)) {
prevTxPause = 1;
prevRxPause = 1;
}
if ((prevRxPause == 0) && (prevTxPause == 0)) {
prevAutonegValue = SK_FALSE;
}
/*
** perform modifications regarding the changes
** requested by the operator
*/
if (epause->autoneg != prevAutonegValue) {
if (epause->autoneg == AUTONEG_DISABLE) {
*Buf = (char) SK_FLOW_MODE_NONE;
} else {
*Buf = (char) SK_FLOW_MODE_SYMMETRIC;
}
} else {
if(epause->rx_pause && epause->tx_pause) {
*Buf = (char) SK_FLOW_MODE_SYMMETRIC;
} else if (epause->rx_pause && !epause->tx_pause) {
*Buf = (char) SK_FLOW_MODE_SYM_OR_REM;
} else if(!epause->rx_pause && epause->tx_pause) {
*Buf = (char) SK_FLOW_MODE_LOC_SEND;
} else {
*Buf = (char) SK_FLOW_MODE_NONE;
}
}
Ret = SkPnmiSetVar(pAC, pAC->IoBase, OID_SKGE_FLOWCTRL_MODE,
&Buf, &Len, Instance, pNet->NetNr);
if (Ret != SK_PNMI_ERR_OK) {
SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_CTRL,
("ethtool (sk98lin): error changing rx/tx pause (%i)\n", Ret));
} else {
Len = 1; /* set buffer length to correct value */
}
/*
** It may be that autoneg has been disabled! Therefore
** set the speed to the previously used value...
*/
*Buf = (char) PrevSpeedVal;
Ret = SkPnmiSetVar(pAC, pAC->IoBase, OID_SKGE_SPEED_MODE,
&Buf, &Len, Instance, pNet->NetNr);
if (Ret != SK_PNMI_ERR_OK) {
SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_CTRL,
("ethtool (sk98lin): error setting speed (%i)\n", Ret));
}
return 0;
}
#endif
#ifdef ETHTOOL_GCOALESCE
/*****************************************************************************
*
* getModerationParams - retrieves the IRQ moderation settings
*
* Description:
* All current IRQ moderation settings of a selected adapter are placed
* in the passed ethtool_coalesce structure and are returned.
*
* Returns: N/A
*
*/
static void getModerationParams(
SK_AC *pAC, /* pointer to adapter control context */
int port, /* the port of the selected adapter */
struct ethtool_coalesce *ecoalesc) /* IRQ moderation struct for results */
{
DIM_INFO *Info = &pAC->DynIrqModInfo;
SK_BOOL UseTxIrqModeration = SK_FALSE;
SK_BOOL UseRxIrqModeration = SK_FALSE;
if (Info->IntModTypeSelect != C_INT_MOD_NONE) {
if (CHIP_ID_YUKON_2(pAC)) {
UseRxIrqModeration = SK_TRUE;
UseTxIrqModeration = SK_TRUE;
} else {
if ((Info->MaskIrqModeration == IRQ_MASK_RX_ONLY) ||
(Info->MaskIrqModeration == IRQ_MASK_SP_RX) ||
(Info->MaskIrqModeration == IRQ_MASK_RX_TX_SP)) {
UseRxIrqModeration = SK_TRUE;
}
if ((Info->MaskIrqModeration == IRQ_MASK_TX_ONLY) ||
(Info->MaskIrqModeration == IRQ_MASK_SP_TX) ||
(Info->MaskIrqModeration == IRQ_MASK_RX_TX_SP)) {
UseTxIrqModeration = SK_TRUE;
}
}
if (UseRxIrqModeration) {
ecoalesc->rx_coalesce_usecs = 1000000 / Info->MaxModIntsPerSec;
}
if (UseTxIrqModeration) {
ecoalesc->tx_coalesce_usecs = 1000000 / Info->MaxModIntsPerSec;
}
if (Info->IntModTypeSelect == C_INT_MOD_DYNAMIC) {
ecoalesc->rate_sample_interval = Info->DynIrqModSampleInterval;
if (UseRxIrqModeration) {
ecoalesc->use_adaptive_rx_coalesce = 1;
ecoalesc->rx_coalesce_usecs_low =
1000000 / Info->MaxModIntsPerSecLowerLimit;
ecoalesc->rx_coalesce_usecs_high =
1000000 / Info->MaxModIntsPerSecUpperLimit;
}
if (UseTxIrqModeration) {
ecoalesc->use_adaptive_tx_coalesce = 1;
ecoalesc->tx_coalesce_usecs_low =
1000000 / Info->MaxModIntsPerSecLowerLimit;
ecoalesc->tx_coalesce_usecs_high =
1000000 / Info->MaxModIntsPerSecUpperLimit;
}
}
}
}
#endif
#ifdef ETHTOOL_SCOALESCE
/*****************************************************************************
*
* setModerationParams - configures the IRQ moderation of an adapter
*
* Description:
* Depending on the desired IRQ moderation parameters, either a) static,
* b) dynamic or c) no moderation is configured.
*
* Returns:
* ==0: everything fine, no error
* !=0: the return value is the error code of the failure
*
* Notes:
* The supported timeframe for the coalesced interrupts ranges from
* 33.333us (30 IntsPerSec) down to 25us (40.000 IntsPerSec).
* Any requested value that is not in this range will abort the request!
*/
static int setModerationParams(
SK_AC *pAC, /* pointer to adapter control context */
int port, /* the port of the selected adapter */
struct ethtool_coalesce *ecoalesc) /* IRQ moderation struct with params */
{
DIM_INFO *Info = &pAC->DynIrqModInfo;
int PrevModeration = Info->IntModTypeSelect;
Info->IntModTypeSelect = C_INT_MOD_NONE; /* initial default */
if ((ecoalesc->rx_coalesce_usecs) || (ecoalesc->tx_coalesce_usecs)) {
if (ecoalesc->rx_coalesce_usecs) {
if ((ecoalesc->rx_coalesce_usecs < 25) ||
(ecoalesc->rx_coalesce_usecs > 33333)) {
return -EINVAL;
}
}
if (ecoalesc->tx_coalesce_usecs) {
if ((ecoalesc->tx_coalesce_usecs < 25) ||
(ecoalesc->tx_coalesce_usecs > 33333)) {
return -EINVAL;
}
}
if (!CHIP_ID_YUKON_2(pAC)) {
if ((Info->MaskIrqModeration == IRQ_MASK_SP_RX) ||
(Info->MaskIrqModeration == IRQ_MASK_SP_TX) ||
(Info->MaskIrqModeration == IRQ_MASK_RX_TX_SP)) {
Info->MaskIrqModeration = IRQ_MASK_SP_ONLY;
}
}
Info->IntModTypeSelect = C_INT_MOD_STATIC;
if (ecoalesc->rx_coalesce_usecs) {
Info->MaxModIntsPerSec =
1000000 / ecoalesc->rx_coalesce_usecs;
if (!CHIP_ID_YUKON_2(pAC)) {
if (Info->MaskIrqModeration == IRQ_MASK_TX_ONLY) {
Info->MaskIrqModeration = IRQ_MASK_TX_RX;
}
if (Info->MaskIrqModeration == IRQ_MASK_SP_ONLY) {
Info->MaskIrqModeration = IRQ_MASK_SP_RX;
}
if (Info->MaskIrqModeration == IRQ_MASK_SP_TX) {
Info->MaskIrqModeration = IRQ_MASK_RX_TX_SP;
}
} else {
Info->MaskIrqModeration = Y2_IRQ_MASK;
}
}
if (ecoalesc->tx_coalesce_usecs) {
Info->MaxModIntsPerSec =
1000000 / ecoalesc->tx_coalesce_usecs;
if (!CHIP_ID_YUKON_2(pAC)) {
if (Info->MaskIrqModeration == IRQ_MASK_RX_ONLY) {
Info->MaskIrqModeration = IRQ_MASK_TX_RX;
}
if (Info->MaskIrqModeration == IRQ_MASK_SP_ONLY) {
Info->MaskIrqModeration = IRQ_MASK_SP_TX;
}
if (Info->MaskIrqModeration == IRQ_MASK_SP_RX) {
Info->MaskIrqModeration = IRQ_MASK_RX_TX_SP;
}
} else {
Info->MaskIrqModeration = Y2_IRQ_MASK;
}
}
}
if ((ecoalesc->rate_sample_interval) ||
(ecoalesc->rx_coalesce_usecs_low) ||
(ecoalesc->tx_coalesce_usecs_low) ||
(ecoalesc->rx_coalesce_usecs_high)||
(ecoalesc->tx_coalesce_usecs_high)) {
if (ecoalesc->rate_sample_interval) {
if ((ecoalesc->rate_sample_interval < 1) ||
(ecoalesc->rate_sample_interval > 10)) {
return -EINVAL;
}
}
if (ecoalesc->rx_coalesce_usecs_low) {
if ((ecoalesc->rx_coalesce_usecs_low < 25) ||
(ecoalesc->rx_coalesce_usecs_low > 33333)) {
return -EINVAL;
}
}
if (ecoalesc->rx_coalesce_usecs_high) {
if ((ecoalesc->rx_coalesce_usecs_high < 25) ||
(ecoalesc->rx_coalesce_usecs_high > 33333)) {
return -EINVAL;
}
}
if (ecoalesc->tx_coalesce_usecs_low) {
if ((ecoalesc->tx_coalesce_usecs_low < 25) ||
(ecoalesc->tx_coalesce_usecs_low > 33333)) {
return -EINVAL;
}
}
if (ecoalesc->tx_coalesce_usecs_high) {
if ((ecoalesc->tx_coalesce_usecs_high < 25) ||
(ecoalesc->tx_coalesce_usecs_high > 33333)) {
return -EINVAL;
}
}
Info->IntModTypeSelect = C_INT_MOD_DYNAMIC;
if (ecoalesc->rate_sample_interval) {
Info->DynIrqModSampleInterval =
ecoalesc->rate_sample_interval;
}
if (ecoalesc->rx_coalesce_usecs_low) {
Info->MaxModIntsPerSecLowerLimit =
1000000 / ecoalesc->rx_coalesce_usecs_low;
}
if (ecoalesc->tx_coalesce_usecs_low) {
Info->MaxModIntsPerSecLowerLimit =
1000000 / ecoalesc->tx_coalesce_usecs_low;
}
if (ecoalesc->rx_coalesce_usecs_high) {
Info->MaxModIntsPerSecUpperLimit =
1000000 / ecoalesc->rx_coalesce_usecs_high;
}
if (ecoalesc->tx_coalesce_usecs_high) {
Info->MaxModIntsPerSecUpperLimit =
1000000 / ecoalesc->tx_coalesce_usecs_high;
}
}
if ((PrevModeration == C_INT_MOD_NONE) &&
(Info->IntModTypeSelect != C_INT_MOD_NONE)) {
SkDimEnableModerationIfNeeded(pAC);
}
if (PrevModeration != C_INT_MOD_NONE) {
SkDimDisableModeration(pAC, PrevModeration);
if (Info->IntModTypeSelect != C_INT_MOD_NONE) {
SkDimEnableModerationIfNeeded(pAC);
}
}
return 0;
}
#endif
#ifdef ETHTOOL_GWOL
/*****************************************************************************
*
* getWOLsettings - retrieves the WOL settings of the selected adapter
*
* Description:
* All current WOL settings of a selected adapter are placed in the
* passed ethtool_wolinfo structure and are returned to the caller.
*
* Returns: N/A
*
*/
static void getWOLsettings(
SK_AC *pAC, /* pointer to adapter control context */
int port, /* the port of the selected adapter */
struct ethtool_wolinfo *ewol) /* mandatory WOL structure for results */
{
ewol->supported = pAC->WolInfo.SupportedWolOptions;
ewol->wolopts = pAC->WolInfo.ConfiguredWolOptions;
return;
}
#endif
#ifdef ETHTOOL_SWOL
/*****************************************************************************
*
* setWOLsettings - configures the WOL settings of a selected adapter
*
* Description:
* The WOL settings of a selected adapter are configured regarding
* the parameters in the passed ethtool_wolinfo structure.
* Note that currently only wake on magic packet is supported!
*
* Returns:
* ==0: everything fine, no error
* !=0: the return value is the error code of the failure
*/
static int setWOLsettings(
SK_AC *pAC, /* pointer to adapter control context */
int port, /* the port of the selected adapter */
struct ethtool_wolinfo *ewol) /* WOL structure containing settings */
{
if (((ewol->wolopts & WAKE_MAGIC) == WAKE_MAGIC) || (ewol->wolopts == 0)) {
pAC->WolInfo.ConfiguredWolOptions = ewol->wolopts;
return 0;
}
return -EFAULT;
}
#endif
#ifdef ETHTOOL_GDRVINFO
/*****************************************************************************
*
* getDriverInfo - returns generic driver and adapter information
*
* Description:
* Generic driver information is returned via this function, such as
* the name of the driver, its version and and firmware version.
* In addition to this, the location of the selected adapter is
* returned as a bus info string (e.g. '01:05.0').
*
* Returns: N/A
*
*/
static void getDriverInfo(
SK_AC *pAC, /* pointer to adapter control context */
int port, /* the port of the selected adapter */
struct ethtool_drvinfo *edrvinfo) /* mandatory info structure for results */
{
char versionString[32];
snprintf(versionString, 32, "%s (%s)", VER_STRING, PATCHLEVEL);
strncpy(edrvinfo->driver, DRIVER_FILE_NAME , 32);
strncpy(edrvinfo->version, versionString , 32);
strncpy(edrvinfo->fw_version, "N/A", 32);
strncpy(edrvinfo->bus_info, pci_name(pAC->PciDev), 32);
#ifdef ETHTOOL_GSTATS
edrvinfo->n_stats = SK98LIN_STATS_LEN;
#endif
}
#endif
#ifdef ETHTOOL_PHYS_ID
/*****************************************************************************
*
* startLocateNIC - start the locate NIC feature of the elected adapter
*
* Description:
* This function is used if the user want to locate a particular NIC.
* All LEDs are regularly switched on and off, so the NIC can easily
* be identified.
*
* Returns:
* ==0: everything fine, no error, locateNIC test was started
* !=0: one locateNIC test runs already
*
*/
static int startLocateNIC(
SK_AC *pAC, /* pointer to adapter control context */
int port, /* the port of the selected adapter */
struct ethtool_value *blinkSecs) /* how long the LEDs should blink in seconds */
{
struct SK_NET_DEVICE *pDev = pAC->dev[port];
int OtherPort = (port) ? 0 : 1;
struct SK_NET_DEVICE *pOtherDev = pAC->dev[OtherPort];
if (isLocateNICrunning) {
return -EFAULT;
}
isLocateNICrunning = SK_TRUE;
currentPortIndex = port;
isDualNetCard = (pDev != pOtherDev) ? SK_TRUE : SK_FALSE;
if (netif_running(pAC->dev[port])) {
boardWasDown[0] = SK_FALSE;
} else {
(*pDev->open)(pDev);
boardWasDown[0] = SK_TRUE;
}
if (isDualNetCard) {
if (netif_running(pAC->dev[OtherPort])) {
boardWasDown[1] = SK_FALSE;
} else {
(*pOtherDev->open)(pOtherDev);
boardWasDown[1] = SK_TRUE;
}
}
if ((blinkSecs->data < 1) || (blinkSecs->data > 30)) {
blinkSecs->data = 3; /* three seconds default */
}
nbrBlinkQuarterSeconds = 4*blinkSecs->data;
init_timer(&locateNICtimer);
locateNICtimer.function = toggleLeds;
locateNICtimer.data = (unsigned long) pAC;
locateNICtimer.expires = jiffies + HZ; /* initially 1sec */
add_timer(&locateNICtimer);
return 0;
}
/*****************************************************************************
*
* toggleLeds - Changes the LED state of an adapter
*
* Description:
* This function changes the current state of all LEDs of an adapter so
* that it can be located by a user. If the requested time interval for
* this test has elapsed, this function cleans up everything that was
* temporarily setup during the locate NIC test. This involves of course
* also closing or opening any adapter so that the initial board state
* is recovered.
*
* Returns: N/A
*
*/
static void toggleLeds(
unsigned long ptr) /* holds the pointer to adapter control context */
{
SK_AC *pAC = (SK_AC *) ptr;
int port = currentPortIndex;
SK_IOC IoC = pAC->IoBase;
struct SK_NET_DEVICE *pDev = pAC->dev[port];
int OtherPort = (port) ? 0 : 1;
struct SK_NET_DEVICE *pOtherDev = pAC->dev[OtherPort];
SK_U16 YukLedOn = (PHY_M_LED_MO_DUP(MO_LED_ON) |
PHY_M_LED_MO_10(MO_LED_ON) |
PHY_M_LED_MO_100(MO_LED_ON) |
PHY_M_LED_MO_1000(MO_LED_ON) |
PHY_M_LED_MO_RX(MO_LED_ON));
SK_U16 YukLedOff = (PHY_M_LED_MO_DUP(MO_LED_OFF) |
PHY_M_LED_MO_10(MO_LED_OFF) |
PHY_M_LED_MO_100(MO_LED_OFF) |
PHY_M_LED_MO_1000(MO_LED_OFF) |
PHY_M_LED_MO_RX(MO_LED_OFF));
nbrBlinkQuarterSeconds--;
if (nbrBlinkQuarterSeconds <= 0) {
(*pDev->stop)(pDev);
if (isDualNetCard) {
(*pOtherDev->stop)(pOtherDev);
}
if (!boardWasDown[0]) {
(*pDev->open)(pDev);
}
if (isDualNetCard) {
(*pOtherDev->open)(pOtherDev);
}
isDualNetCard = SK_FALSE;
isLocateNICrunning = SK_FALSE;
return;
}
doSwitchLEDsOn = (doSwitchLEDsOn) ? SK_FALSE : SK_TRUE;
if (doSwitchLEDsOn) {
if (pAC->GIni.GIGenesis) {
SK_OUT8(IoC,MR_ADDR(port,LNK_LED_REG),(SK_U8)SK_LNK_ON);
SkGeYellowLED(pAC,IoC,LED_ON >> 1);
SkGeXmitLED(pAC,IoC,MR_ADDR(port,RX_LED_INI),SK_LED_TST);
if (pAC->GIni.GP[port].PhyType == SK_PHY_BCOM) {
SkXmPhyWrite(pAC,IoC,port,PHY_BCOM_P_EXT_CTRL,PHY_B_PEC_LED_ON);
} else if (pAC->GIni.GP[port].PhyType == SK_PHY_LONE) {
SkXmPhyWrite(pAC,IoC,port,PHY_LONE_LED_CFG,0x0800);
} else {
SkGeXmitLED(pAC,IoC,MR_ADDR(port,TX_LED_INI),SK_LED_TST);
}
} else {
SkGmPhyWrite(pAC,IoC,port,PHY_MARV_LED_CTRL,0);
SkGmPhyWrite(pAC,IoC,port,PHY_MARV_LED_OVER,YukLedOn);
}
} else {
if (pAC->GIni.GIGenesis) {
SK_OUT8(IoC,MR_ADDR(port,LNK_LED_REG),(SK_U8)SK_LNK_OFF);
SkGeYellowLED(pAC,IoC,LED_OFF >> 1);
SkGeXmitLED(pAC,IoC,MR_ADDR(port,RX_LED_INI),SK_LED_DIS);
if (pAC->GIni.GP[port].PhyType == SK_PHY_BCOM) {
SkXmPhyWrite(pAC,IoC,port,PHY_BCOM_P_EXT_CTRL,PHY_B_PEC_LED_OFF);
} else if (pAC->GIni.GP[port].PhyType == SK_PHY_LONE) {
SkXmPhyWrite(pAC,IoC,port,PHY_LONE_LED_CFG,PHY_L_LC_LEDT);
} else {
SkGeXmitLED(pAC,IoC,MR_ADDR(port,TX_LED_INI),SK_LED_DIS);
}
} else {
SkGmPhyWrite(pAC,IoC,port,PHY_MARV_LED_CTRL,0);
SkGmPhyWrite(pAC,IoC,port,PHY_MARV_LED_OVER,YukLedOff);
}
}
locateNICtimer.function = toggleLeds;
locateNICtimer.data = (unsigned long) pAC;
locateNICtimer.expires = jiffies + (HZ/4); /* 250ms */
add_timer(&locateNICtimer);
}
#endif
/*****************************************************************************
*
* getPortNumber - evaluates the port number of an interface
*
* Description:
* It may be that the current interface refers to one which is located
* on a dual net adapter. Hence, this function will return the correct
* port for further use.
*
* Returns:
* the port number that corresponds to the selected adapter
*
*/
static int getPortNumber(
struct net_device *netdev, /* the pointer to netdev structure */
struct ifreq *ifr) /* what interface the request refers to? */
{
DEV_NET *pNet = (DEV_NET*) netdev->priv;
SK_AC *pAC = pNet->pAC;
if (pAC->dev[1] != pAC->dev[0]) {
if (!strcmp(pAC->dev[1]->name, ifr->ifr_name)) {
return 1; /* port index 1 */
}
}
return 0;
}
/*******************************************************************************
*
* End of file
*
******************************************************************************/
#endif