1 /******************************************************************************
4 * Project: GEnesis, PCI Gigabit Ethernet Adapter
5 * Version: $Revision: 1.7 $
6 * Date: $Date: 2004/09/29 13:32:07 $
7 * Purpose: All functions regarding ethtool handling
9 ******************************************************************************/
11 /******************************************************************************
13 * (C)Copyright 1998-2002 SysKonnect GmbH.
14 * (C)Copyright 2002-2004 Marvell.
16 * Driver for Marvell Yukon/2 chipset and SysKonnect Gigabit Ethernet
19 * Author: Ralph Roesler (rroesler@syskonnect.de)
20 * Mirko Lindner (mlindner@syskonnect.de)
22 * Address all question to: linux@syskonnect.de
24 * The technical manual for the adapters is available from SysKonnect's
25 * web pages: www.syskonnect.com
27 * This program is free software; you can redistribute it and/or modify
28 * it under the terms of the GNU General Public License as published by
29 * the Free Software Foundation; either version 2 of the License, or
30 * (at your option) any later version.
32 * The information in this file is provided "AS IS" without warranty.
34 *****************************************************************************/
36 #include "h/skdrv1st.h"
37 #include "h/skdrv2nd.h"
38 #include "h/skversion.h"
40 #include <linux/ethtool.h>
41 #include <linux/timer.h>
42 #include <linux/delay.h>
44 /******************************************************************************
48 *****************************************************************************/
50 #define SUPP_COPPER_ALL (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
51 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
52 SUPPORTED_1000baseT_Half| SUPPORTED_1000baseT_Full| \
55 #define ADV_COPPER_ALL (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
56 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
57 ADVERTISED_1000baseT_Half| ADVERTISED_1000baseT_Full| \
60 #define SUPP_FIBRE_ALL (SUPPORTED_1000baseT_Full | \
64 #define ADV_FIBRE_ALL (ADVERTISED_1000baseT_Full | \
69 /******************************************************************************
73 *****************************************************************************/
75 /*****************************************************************************
77 * getSettings - retrieves the current settings of the selected adapter
80 * The current configuration of the selected adapter is returned.
81 * This configuration involves a)speed, b)duplex and c)autoneg plus
82 * a number of other variables.
87 static int getSettings(struct net_device
*dev
, struct ethtool_cmd
*ecmd
)
89 const DEV_NET
*pNet
= netdev_priv(dev
);
90 int port
= pNet
->PortNr
;
91 const SK_AC
*pAC
= pNet
->pAC
;
92 const SK_GEPORT
*pPort
= &pAC
->GIni
.GP
[port
];
94 static int DuplexAutoNegConfMap
[9][3]= {
97 { SK_LMODE_HALF
, DUPLEX_HALF
, AUTONEG_DISABLE
},
98 { SK_LMODE_FULL
, DUPLEX_FULL
, AUTONEG_DISABLE
},
99 { SK_LMODE_AUTOHALF
, DUPLEX_HALF
, AUTONEG_ENABLE
},
100 { SK_LMODE_AUTOFULL
, DUPLEX_FULL
, AUTONEG_ENABLE
},
101 { SK_LMODE_AUTOBOTH
, DUPLEX_FULL
, AUTONEG_ENABLE
},
102 { SK_LMODE_AUTOSENSE
, -1 , -1 },
103 { SK_LMODE_INDETERMINATED
, -1 , -1 }
105 static int SpeedConfMap
[6][2] = {
107 { SK_LSPEED_AUTO
, -1 },
108 { SK_LSPEED_10MBPS
, SPEED_10
},
109 { SK_LSPEED_100MBPS
, SPEED_100
},
110 { SK_LSPEED_1000MBPS
, SPEED_1000
},
111 { SK_LSPEED_INDETERMINATED
, -1 }
113 static int AdvSpeedMap
[6][2] = {
115 { SK_LSPEED_AUTO
, -1 },
116 { SK_LSPEED_10MBPS
, ADVERTISED_10baseT_Half
| ADVERTISED_10baseT_Full
},
117 { SK_LSPEED_100MBPS
, ADVERTISED_100baseT_Half
| ADVERTISED_100baseT_Full
},
118 { SK_LSPEED_1000MBPS
, ADVERTISED_1000baseT_Half
| ADVERTISED_1000baseT_Full
},
119 { SK_LSPEED_INDETERMINATED
, -1 }
122 ecmd
->phy_address
= port
;
123 ecmd
->speed
= SpeedConfMap
[pPort
->PLinkSpeedUsed
][1];
124 ecmd
->duplex
= DuplexAutoNegConfMap
[pPort
->PLinkModeStatus
][1];
125 ecmd
->autoneg
= DuplexAutoNegConfMap
[pPort
->PLinkModeStatus
][2];
126 ecmd
->transceiver
= XCVR_INTERNAL
;
128 if (pAC
->GIni
.GICopperType
) {
129 ecmd
->port
= PORT_TP
;
130 ecmd
->supported
= (SUPP_COPPER_ALL
|SUPPORTED_Autoneg
);
131 if (pAC
->GIni
.GIGenesis
) {
132 ecmd
->supported
&= ~(SUPPORTED_10baseT_Half
);
133 ecmd
->supported
&= ~(SUPPORTED_10baseT_Full
);
134 ecmd
->supported
&= ~(SUPPORTED_100baseT_Half
);
135 ecmd
->supported
&= ~(SUPPORTED_100baseT_Full
);
137 if (pAC
->GIni
.GIChipId
== CHIP_ID_YUKON
) {
138 ecmd
->supported
&= ~(SUPPORTED_1000baseT_Half
);
140 #ifdef CHIP_ID_YUKON_FE
141 if (pAC
->GIni
.GIChipId
== CHIP_ID_YUKON_FE
) {
142 ecmd
->supported
&= ~(SUPPORTED_1000baseT_Half
);
143 ecmd
->supported
&= ~(SUPPORTED_1000baseT_Full
);
147 if (pAC
->GIni
.GP
[0].PLinkSpeed
!= SK_LSPEED_AUTO
) {
148 ecmd
->advertising
= AdvSpeedMap
[pPort
->PLinkSpeed
][1];
149 if (pAC
->GIni
.GIChipId
== CHIP_ID_YUKON
) {
150 ecmd
->advertising
&= ~(SUPPORTED_1000baseT_Half
);
153 ecmd
->advertising
= ecmd
->supported
;
156 if (ecmd
->autoneg
== AUTONEG_ENABLE
)
157 ecmd
->advertising
|= ADVERTISED_Autoneg
;
159 ecmd
->port
= PORT_FIBRE
;
160 ecmd
->supported
= SUPP_FIBRE_ALL
;
161 ecmd
->advertising
= ADV_FIBRE_ALL
;
167 * MIB infrastructure uses instance value starting at 1
168 * based on board and port.
170 static inline u32
pnmiInstance(const DEV_NET
*pNet
)
172 return 1 + (pNet
->pAC
->RlmtNets
== 2) + pNet
->PortNr
;
175 /*****************************************************************************
177 * setSettings - configures the settings of a selected adapter
180 * Possible settings that may be altered are a)speed, b)duplex or
184 * 0: everything fine, no error
185 * <0: the return value is the error code of the failure
187 static int setSettings(struct net_device
*dev
, struct ethtool_cmd
*ecmd
)
189 DEV_NET
*pNet
= netdev_priv(dev
);
190 SK_AC
*pAC
= pNet
->pAC
;
195 if (ecmd
->speed
!= SPEED_10
&& ecmd
->speed
!= SPEED_100
196 && ecmd
->speed
!= SPEED_1000
)
199 if (ecmd
->duplex
!= DUPLEX_HALF
&& ecmd
->duplex
!= DUPLEX_FULL
)
202 if (ecmd
->autoneg
!= AUTONEG_DISABLE
&& ecmd
->autoneg
!= AUTONEG_ENABLE
)
205 if (ecmd
->autoneg
== AUTONEG_DISABLE
)
206 *buf
= (ecmd
->duplex
== DUPLEX_FULL
)
207 ? SK_LMODE_FULL
: SK_LMODE_HALF
;
209 *buf
= (ecmd
->duplex
== DUPLEX_FULL
)
210 ? SK_LMODE_AUTOFULL
: SK_LMODE_AUTOHALF
;
212 instance
= pnmiInstance(pNet
);
213 if (SkPnmiSetVar(pAC
, pAC
->IoBase
, OID_SKGE_LINK_MODE
,
214 &buf
, &len
, instance
, pNet
->NetNr
) != SK_PNMI_ERR_OK
)
217 switch(ecmd
->speed
) {
219 *buf
= SK_LSPEED_1000MBPS
;
222 *buf
= SK_LSPEED_100MBPS
;
225 *buf
= SK_LSPEED_10MBPS
;
228 if (SkPnmiSetVar(pAC
, pAC
->IoBase
, OID_SKGE_SPEED_MODE
,
229 &buf
, &len
, instance
, pNet
->NetNr
) != SK_PNMI_ERR_OK
)
235 /*****************************************************************************
237 * getDriverInfo - returns generic driver and adapter information
240 * Generic driver information is returned via this function, such as
241 * the name of the driver, its version and and firmware version.
242 * In addition to this, the location of the selected adapter is
243 * returned as a bus info string (e.g. '01:05.0').
248 static void getDriverInfo(struct net_device
*dev
, struct ethtool_drvinfo
*info
)
250 const DEV_NET
*pNet
= netdev_priv(dev
);
251 const SK_AC
*pAC
= pNet
->pAC
;
254 snprintf(vers
, sizeof(vers
)-1, VER_STRING
"(v%d.%d)",
255 (pAC
->GIni
.GIPciHwRev
>> 4) & 0xf, pAC
->GIni
.GIPciHwRev
& 0xf);
257 strlcpy(info
->driver
, DRIVER_FILE_NAME
, sizeof(info
->driver
));
258 strcpy(info
->version
, vers
);
259 strcpy(info
->fw_version
, "N/A");
260 strlcpy(info
->bus_info
, pci_name(pAC
->PciDev
), ETHTOOL_BUSINFO_LEN
);
264 * Ethtool statistics support.
266 static const char StringsStats
[][ETH_GSTRING_LEN
] = {
267 "rx_packets", "tx_packets",
268 "rx_bytes", "tx_bytes",
269 "rx_errors", "tx_errors",
270 "rx_dropped", "tx_dropped",
271 "multicasts", "collisions",
272 "rx_length_errors", "rx_buffer_overflow_errors",
273 "rx_crc_errors", "rx_frame_errors",
274 "rx_too_short_errors", "rx_too_long_errors",
275 "rx_carrier_extension_errors", "rx_symbol_errors",
276 "rx_llc_mac_size_errors", "rx_carrier_errors",
277 "rx_jabber_errors", "rx_missed_errors",
278 "tx_abort_collision_errors", "tx_carrier_errors",
279 "tx_buffer_underrun_errors", "tx_heartbeat_errors",
283 static int getStatsCount(struct net_device
*dev
)
285 return ARRAY_SIZE(StringsStats
);
288 static void getStrings(struct net_device
*dev
, u32 stringset
, u8
*data
)
292 memcpy(data
, *StringsStats
, sizeof(StringsStats
));
297 static void getEthtoolStats(struct net_device
*dev
,
298 struct ethtool_stats
*stats
, u64
*data
)
300 const DEV_NET
*pNet
= netdev_priv(dev
);
301 const SK_AC
*pAC
= pNet
->pAC
;
302 const SK_PNMI_STRUCT_DATA
*pPnmiStruct
= &pAC
->PnmiStruct
;
304 *data
++ = pPnmiStruct
->Stat
[0].StatRxOkCts
;
305 *data
++ = pPnmiStruct
->Stat
[0].StatTxOkCts
;
306 *data
++ = pPnmiStruct
->Stat
[0].StatRxOctetsOkCts
;
307 *data
++ = pPnmiStruct
->Stat
[0].StatTxOctetsOkCts
;
308 *data
++ = pPnmiStruct
->InErrorsCts
;
309 *data
++ = pPnmiStruct
->Stat
[0].StatTxSingleCollisionCts
;
310 *data
++ = pPnmiStruct
->RxNoBufCts
;
311 *data
++ = pPnmiStruct
->TxNoBufCts
;
312 *data
++ = pPnmiStruct
->Stat
[0].StatRxMulticastOkCts
;
313 *data
++ = pPnmiStruct
->Stat
[0].StatTxSingleCollisionCts
;
314 *data
++ = pPnmiStruct
->Stat
[0].StatRxRuntCts
;
315 *data
++ = pPnmiStruct
->Stat
[0].StatRxFifoOverflowCts
;
316 *data
++ = pPnmiStruct
->Stat
[0].StatRxFcsCts
;
317 *data
++ = pPnmiStruct
->Stat
[0].StatRxFramingCts
;
318 *data
++ = pPnmiStruct
->Stat
[0].StatRxShortsCts
;
319 *data
++ = pPnmiStruct
->Stat
[0].StatRxTooLongCts
;
320 *data
++ = pPnmiStruct
->Stat
[0].StatRxCextCts
;
321 *data
++ = pPnmiStruct
->Stat
[0].StatRxSymbolCts
;
322 *data
++ = pPnmiStruct
->Stat
[0].StatRxIRLengthCts
;
323 *data
++ = pPnmiStruct
->Stat
[0].StatRxCarrierCts
;
324 *data
++ = pPnmiStruct
->Stat
[0].StatRxJabberCts
;
325 *data
++ = pPnmiStruct
->Stat
[0].StatRxMissedCts
;
326 *data
++ = pAC
->stats
.tx_aborted_errors
;
327 *data
++ = pPnmiStruct
->Stat
[0].StatTxCarrierCts
;
328 *data
++ = pPnmiStruct
->Stat
[0].StatTxFifoUnderrunCts
;
329 *data
++ = pPnmiStruct
->Stat
[0].StatTxCarrierCts
;
330 *data
++ = pAC
->stats
.tx_window_errors
;
334 /*****************************************************************************
336 * toggleLeds - Changes the LED state of an adapter
339 * This function changes the current state of all LEDs of an adapter so
340 * that it can be located by a user.
345 static void toggleLeds(DEV_NET
*pNet
, int on
)
347 SK_AC
*pAC
= pNet
->pAC
;
348 int port
= pNet
->PortNr
;
349 void __iomem
*io
= pAC
->IoBase
;
351 if (pAC
->GIni
.GIGenesis
) {
352 SK_OUT8(io
, MR_ADDR(port
,LNK_LED_REG
),
353 on
? SK_LNK_ON
: SK_LNK_OFF
);
354 SkGeYellowLED(pAC
, io
,
355 on
? (LED_ON
>> 1) : (LED_OFF
>> 1));
356 SkGeXmitLED(pAC
, io
, MR_ADDR(port
,RX_LED_INI
),
357 on
? SK_LED_TST
: SK_LED_DIS
);
359 if (pAC
->GIni
.GP
[port
].PhyType
== SK_PHY_BCOM
)
360 SkXmPhyWrite(pAC
, io
, port
, PHY_BCOM_P_EXT_CTRL
,
361 on
? PHY_B_PEC_LED_ON
: PHY_B_PEC_LED_OFF
);
362 else if (pAC
->GIni
.GP
[port
].PhyType
== SK_PHY_LONE
)
363 SkXmPhyWrite(pAC
, io
, port
, PHY_LONE_LED_CFG
,
364 on
? 0x0800 : PHY_L_LC_LEDT
);
366 SkGeXmitLED(pAC
, io
, MR_ADDR(port
,TX_LED_INI
),
367 on
? SK_LED_TST
: SK_LED_DIS
);
369 const u16 YukLedOn
= (PHY_M_LED_MO_DUP(MO_LED_ON
) |
370 PHY_M_LED_MO_10(MO_LED_ON
) |
371 PHY_M_LED_MO_100(MO_LED_ON
) |
372 PHY_M_LED_MO_1000(MO_LED_ON
) |
373 PHY_M_LED_MO_RX(MO_LED_ON
));
374 const u16 YukLedOff
= (PHY_M_LED_MO_DUP(MO_LED_OFF
) |
375 PHY_M_LED_MO_10(MO_LED_OFF
) |
376 PHY_M_LED_MO_100(MO_LED_OFF
) |
377 PHY_M_LED_MO_1000(MO_LED_OFF
) |
378 PHY_M_LED_MO_RX(MO_LED_OFF
));
381 SkGmPhyWrite(pAC
,io
,port
,PHY_MARV_LED_CTRL
,0);
382 SkGmPhyWrite(pAC
,io
,port
,PHY_MARV_LED_OVER
,
383 on
? YukLedOn
: YukLedOff
);
387 /*****************************************************************************
389 * skGeBlinkTimer - Changes the LED state of an adapter
392 * This function changes the current state of all LEDs of an adapter so
393 * that it can be located by a user. If the requested time interval for
394 * this test has elapsed, this function cleans up everything that was
395 * temporarily setup during the locate NIC test. This involves of course
396 * also closing or opening any adapter so that the initial board state
402 void SkGeBlinkTimer(unsigned long data
)
404 struct net_device
*dev
= (struct net_device
*) data
;
405 DEV_NET
*pNet
= netdev_priv(dev
);
406 SK_AC
*pAC
= pNet
->pAC
;
408 toggleLeds(pNet
, pAC
->LedsOn
);
410 pAC
->LedsOn
= !pAC
->LedsOn
;
411 mod_timer(&pAC
->BlinkTimer
, jiffies
+ HZ
/4);
414 /*****************************************************************************
416 * locateDevice - start the locate NIC feature of the elected adapter
419 * This function is used if the user want to locate a particular NIC.
420 * All LEDs are regularly switched on and off, so the NIC can easily
424 * ==0: everything fine, no error, locateNIC test was started
425 * !=0: one locateNIC test runs already
428 static int locateDevice(struct net_device
*dev
, u32 data
)
430 DEV_NET
*pNet
= netdev_priv(dev
);
431 SK_AC
*pAC
= pNet
->pAC
;
433 if(!data
|| data
> (u32
)(MAX_SCHEDULE_TIMEOUT
/ HZ
))
434 data
= (u32
)(MAX_SCHEDULE_TIMEOUT
/ HZ
);
438 mod_timer(&pAC
->BlinkTimer
, jiffies
);
439 msleep_interruptible(data
* 1000);
440 del_timer_sync(&pAC
->BlinkTimer
);
446 /*****************************************************************************
448 * getPauseParams - retrieves the pause parameters
451 * All current pause parameters of a selected adapter are placed
452 * in the passed ethtool_pauseparam structure and are returned.
457 static void getPauseParams(struct net_device
*dev
, struct ethtool_pauseparam
*epause
)
459 DEV_NET
*pNet
= netdev_priv(dev
);
460 SK_AC
*pAC
= pNet
->pAC
;
461 SK_GEPORT
*pPort
= &pAC
->GIni
.GP
[pNet
->PortNr
];
463 epause
->rx_pause
= (pPort
->PFlowCtrlMode
== SK_FLOW_MODE_SYMMETRIC
) ||
464 (pPort
->PFlowCtrlMode
== SK_FLOW_MODE_SYM_OR_REM
);
466 epause
->tx_pause
= epause
->rx_pause
|| (pPort
->PFlowCtrlMode
== SK_FLOW_MODE_LOC_SEND
);
467 epause
->autoneg
= epause
->rx_pause
|| epause
->tx_pause
;
470 /*****************************************************************************
472 * setPauseParams - configures the pause parameters of an adapter
475 * This function sets the Rx or Tx pause parameters
478 * ==0: everything fine, no error
479 * !=0: the return value is the error code of the failure
481 static int setPauseParams(struct net_device
*dev
, struct ethtool_pauseparam
*epause
)
483 DEV_NET
*pNet
= netdev_priv(dev
);
484 SK_AC
*pAC
= pNet
->pAC
;
485 SK_GEPORT
*pPort
= &pAC
->GIni
.GP
[pNet
->PortNr
];
486 u32 instance
= pnmiInstance(pNet
);
487 struct ethtool_pauseparam old
;
488 u8 oldspeed
= pPort
->PLinkSpeedUsed
;
494 ** we have to determine the current settings to see if
495 ** the operator requested any modification of the flow
496 ** control parameters...
498 getPauseParams(dev
, &old
);
501 ** perform modifications regarding the changes
502 ** requested by the operator
504 if (epause
->autoneg
!= old
.autoneg
)
505 *buf
= epause
->autoneg
? SK_FLOW_MODE_NONE
: SK_FLOW_MODE_SYMMETRIC
;
507 if (epause
->rx_pause
&& epause
->tx_pause
)
508 *buf
= SK_FLOW_MODE_SYMMETRIC
;
509 else if (epause
->rx_pause
&& !epause
->tx_pause
)
510 *buf
= SK_FLOW_MODE_SYM_OR_REM
;
511 else if (!epause
->rx_pause
&& epause
->tx_pause
)
512 *buf
= SK_FLOW_MODE_LOC_SEND
;
514 *buf
= SK_FLOW_MODE_NONE
;
517 ret
= SkPnmiSetVar(pAC
, pAC
->IoBase
, OID_SKGE_FLOWCTRL_MODE
,
518 &buf
, &len
, instance
, pNet
->NetNr
);
520 if (ret
!= SK_PNMI_ERR_OK
) {
521 SK_DBG_MSG(NULL
, SK_DBGMOD_DRV
, SK_DBGCAT_CTRL
,
522 ("ethtool (sk98lin): error changing rx/tx pause (%i)\n", ret
));
527 ** It may be that autoneg has been disabled! Therefore
528 ** set the speed to the previously used value...
530 if (!epause
->autoneg
) {
532 ret
= SkPnmiSetVar(pAC
, pAC
->IoBase
, OID_SKGE_SPEED_MODE
,
533 &oldspeed
, &len
, instance
, pNet
->NetNr
);
534 if (ret
!= SK_PNMI_ERR_OK
)
535 SK_DBG_MSG(NULL
, SK_DBGMOD_DRV
, SK_DBGCAT_CTRL
,
536 ("ethtool (sk98lin): error setting speed (%i)\n", ret
));
539 return ret
? -EIO
: 0;
542 /* Only Yukon supports checksum offload. */
543 static int setScatterGather(struct net_device
*dev
, u32 data
)
545 DEV_NET
*pNet
= netdev_priv(dev
);
546 SK_AC
*pAC
= pNet
->pAC
;
548 if (pAC
->GIni
.GIChipId
== CHIP_ID_GENESIS
)
550 return ethtool_op_set_sg(dev
, data
);
553 static int setTxCsum(struct net_device
*dev
, u32 data
)
555 DEV_NET
*pNet
= netdev_priv(dev
);
556 SK_AC
*pAC
= pNet
->pAC
;
558 if (pAC
->GIni
.GIChipId
== CHIP_ID_GENESIS
)
561 return ethtool_op_set_tx_csum(dev
, data
);
564 static u32
getRxCsum(struct net_device
*dev
)
566 DEV_NET
*pNet
= netdev_priv(dev
);
567 SK_AC
*pAC
= pNet
->pAC
;
569 return pAC
->RxPort
[pNet
->PortNr
].RxCsum
;
572 static int setRxCsum(struct net_device
*dev
, u32 data
)
574 DEV_NET
*pNet
= netdev_priv(dev
);
575 SK_AC
*pAC
= pNet
->pAC
;
577 if (pAC
->GIni
.GIChipId
== CHIP_ID_GENESIS
)
580 pAC
->RxPort
[pNet
->PortNr
].RxCsum
= data
!= 0;
584 struct ethtool_ops SkGeEthtoolOps
= {
585 .get_settings
= getSettings
,
586 .set_settings
= setSettings
,
587 .get_drvinfo
= getDriverInfo
,
588 .get_strings
= getStrings
,
589 .get_stats_count
= getStatsCount
,
590 .get_ethtool_stats
= getEthtoolStats
,
591 .phys_id
= locateDevice
,
592 .get_pauseparam
= getPauseParams
,
593 .set_pauseparam
= setPauseParams
,
594 .get_link
= ethtool_op_get_link
,
595 .get_perm_addr
= ethtool_op_get_perm_addr
,
596 .get_sg
= ethtool_op_get_sg
,
597 .set_sg
= setScatterGather
,
598 .get_tx_csum
= ethtool_op_get_tx_csum
,
599 .set_tx_csum
= setTxCsum
,
600 .get_rx_csum
= getRxCsum
,
601 .set_rx_csum
= setRxCsum
,