[PATCH] sk98lin: allow ethtool checksum on/off per port
[linux-2.6.git] / drivers / net / sk98lin / skethtool.c
1 /******************************************************************************
2  *
3  * Name:        skethtool.c
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
8  *
9  ******************************************************************************/
10
11 /******************************************************************************
12  *
13  *      (C)Copyright 1998-2002 SysKonnect GmbH.
14  *      (C)Copyright 2002-2004 Marvell.
15  *
16  *      Driver for Marvell Yukon/2 chipset and SysKonnect Gigabit Ethernet 
17  *      Server Adapters.
18  *
19  *      Author: Ralph Roesler (rroesler@syskonnect.de)
20  *              Mirko Lindner (mlindner@syskonnect.de)
21  *
22  *      Address all question to: linux@syskonnect.de
23  *
24  *      The technical manual for the adapters is available from SysKonnect's
25  *      web pages: www.syskonnect.com
26  *      
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.
31  *
32  *      The information in this file is provided "AS IS" without warranty.
33  *
34  *****************************************************************************/
35
36 #include "h/skdrv1st.h"
37 #include "h/skdrv2nd.h"
38 #include "h/skversion.h"
39
40 #include <linux/ethtool.h>
41 #include <linux/timer.h>
42 #include <linux/delay.h>
43
44 /******************************************************************************
45  *
46  * Defines
47  *
48  *****************************************************************************/
49
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| \
53                          SUPPORTED_TP)
54
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| \
58                          ADVERTISED_TP)
59
60 #define SUPP_FIBRE_ALL  (SUPPORTED_1000baseT_Full | \
61                          SUPPORTED_FIBRE          | \
62                          SUPPORTED_Autoneg)
63
64 #define ADV_FIBRE_ALL   (ADVERTISED_1000baseT_Full | \
65                          ADVERTISED_FIBRE          | \
66                          ADVERTISED_Autoneg)
67
68
69 /******************************************************************************
70  *
71  * Local Functions
72  *
73  *****************************************************************************/
74
75 /*****************************************************************************
76  *
77  *      getSettings - retrieves the current settings of the selected adapter
78  *
79  * Description:
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.
83  *
84  * Returns:    always 0
85  *
86  */
87 static int getSettings(struct net_device *dev, struct ethtool_cmd *ecmd)
88 {
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];
93
94         static int DuplexAutoNegConfMap[9][3]= {
95                 { -1                     , -1         , -1              },
96                 { 0                      , -1         , -1              },
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              }
104         };
105         static int SpeedConfMap[6][2] = {
106                 { 0                       , -1         },
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         }
112         };
113         static int AdvSpeedMap[6][2] = {
114                 { 0                       , -1         },
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         }
120         };
121
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;
127
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);
136                 } else {
137                         if (pAC->GIni.GIChipId == CHIP_ID_YUKON) {
138                                 ecmd->supported &= ~(SUPPORTED_1000baseT_Half);
139                         } 
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);
144                         }
145 #endif
146                 }
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);
151                         } 
152                 } else {
153                         ecmd->advertising = ecmd->supported;
154                 }
155
156                 if (ecmd->autoneg == AUTONEG_ENABLE) 
157                         ecmd->advertising |= ADVERTISED_Autoneg;
158         } else {
159                 ecmd->port        = PORT_FIBRE;
160                 ecmd->supported   = SUPP_FIBRE_ALL;
161                 ecmd->advertising = ADV_FIBRE_ALL;
162         }
163         return 0;
164 }
165
166 /*
167  * MIB infrastructure uses instance value starting at 1
168  * based on board and port.
169  */
170 static inline u32 pnmiInstance(const DEV_NET *pNet)
171 {
172         return 1 + (pNet->pAC->RlmtNets == 2) + pNet->PortNr;
173 }
174
175 /*****************************************************************************
176  *
177  *      setSettings - configures the settings of a selected adapter
178  *
179  * Description:
180  *      Possible settings that may be altered are a)speed, b)duplex or 
181  *      c)autonegotiation.
182  *
183  * Returns:
184  *      0:      everything fine, no error
185  *      <0:     the return value is the error code of the failure 
186  */
187 static int setSettings(struct net_device *dev, struct ethtool_cmd *ecmd)
188 {
189         DEV_NET *pNet = netdev_priv(dev);
190         SK_AC *pAC = pNet->pAC;
191         u32 instance;
192         char buf[4];
193         int len = 1;
194
195         if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100 
196             && ecmd->speed != SPEED_1000)
197                 return -EINVAL;
198
199         if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
200                 return -EINVAL;
201
202         if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
203                 return -EINVAL;
204
205         if (ecmd->autoneg == AUTONEG_DISABLE)
206                 *buf = (ecmd->duplex == DUPLEX_FULL) 
207                         ? SK_LMODE_FULL : SK_LMODE_HALF;
208         else
209                 *buf = (ecmd->duplex == DUPLEX_FULL) 
210                         ? SK_LMODE_AUTOFULL : SK_LMODE_AUTOHALF;
211         
212         instance = pnmiInstance(pNet);
213         if (SkPnmiSetVar(pAC, pAC->IoBase, OID_SKGE_LINK_MODE, 
214                            &buf, &len, instance, pNet->NetNr) != SK_PNMI_ERR_OK)
215                 return -EINVAL;
216
217         switch(ecmd->speed) {
218         case SPEED_1000:
219                 *buf = SK_LSPEED_1000MBPS;
220                 break;
221         case SPEED_100:
222                 *buf = SK_LSPEED_100MBPS;
223                 break;
224         case SPEED_10:
225                 *buf = SK_LSPEED_10MBPS;
226         }
227
228         if (SkPnmiSetVar(pAC, pAC->IoBase, OID_SKGE_SPEED_MODE, 
229                          &buf, &len, instance, pNet->NetNr) != SK_PNMI_ERR_OK)
230                 return -EINVAL;
231
232         return 0;
233 }
234
235 /*****************************************************************************
236  *
237  *      getDriverInfo - returns generic driver and adapter information
238  *
239  * Description:
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').
244  *      
245  * Returns:     N/A
246  *
247  */
248 static void getDriverInfo(struct net_device *dev, struct ethtool_drvinfo *info)
249 {
250         const DEV_NET   *pNet = netdev_priv(dev);
251         const SK_AC *pAC = pNet->pAC;
252         char vers[32];
253
254         snprintf(vers, sizeof(vers)-1, VER_STRING "(v%d.%d)",
255                 (pAC->GIni.GIPciHwRev >> 4) & 0xf, pAC->GIni.GIPciHwRev & 0xf);
256
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);
261 }
262
263 /*
264  * Ethtool statistics support.
265  */
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",
280         "tx_window_errors",
281 };
282
283 static int getStatsCount(struct net_device *dev)
284 {
285         return ARRAY_SIZE(StringsStats);
286 }
287
288 static void getStrings(struct net_device *dev, u32 stringset, u8 *data)
289 {
290         switch(stringset) {
291         case ETH_SS_STATS:
292                 memcpy(data, *StringsStats, sizeof(StringsStats));
293                 break;
294         }
295 }
296
297 static void getEthtoolStats(struct net_device *dev,
298                             struct ethtool_stats *stats, u64 *data)
299 {
300         const DEV_NET   *pNet = netdev_priv(dev);
301         const SK_AC *pAC = pNet->pAC;
302         const SK_PNMI_STRUCT_DATA *pPnmiStruct = &pAC->PnmiStruct;
303
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;
331 }
332
333
334 /*****************************************************************************
335  *
336  *      toggleLeds - Changes the LED state of an adapter
337  *
338  * Description:
339  *      This function changes the current state of all LEDs of an adapter so
340  *      that it can be located by a user. 
341  *
342  * Returns:     N/A
343  *
344  */
345 static void toggleLeds(DEV_NET *pNet, int on)
346 {
347         SK_AC *pAC = pNet->pAC;
348         int port = pNet->PortNr;
349         void __iomem *io = pAC->IoBase;
350
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);
358
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);
365                 else
366                         SkGeXmitLED(pAC, io, MR_ADDR(port,TX_LED_INI),
367                                     on ? SK_LED_TST : SK_LED_DIS);
368         } else {
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));
379         
380
381                 SkGmPhyWrite(pAC,io,port,PHY_MARV_LED_CTRL,0);
382                 SkGmPhyWrite(pAC,io,port,PHY_MARV_LED_OVER, 
383                              on ? YukLedOn : YukLedOff);
384         }
385 }
386
387 /*****************************************************************************
388  *
389  *      skGeBlinkTimer - Changes the LED state of an adapter
390  *
391  * Description:
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 
397  *      is recovered.
398  *
399  * Returns:     N/A
400  *
401  */
402 void SkGeBlinkTimer(unsigned long data)
403 {
404         struct net_device *dev = (struct net_device *) data;
405         DEV_NET *pNet = netdev_priv(dev);
406         SK_AC *pAC = pNet->pAC;
407
408         toggleLeds(pNet, pAC->LedsOn);
409
410         pAC->LedsOn = !pAC->LedsOn;
411         mod_timer(&pAC->BlinkTimer, jiffies + HZ/4);
412 }
413
414 /*****************************************************************************
415  *
416  *      locateDevice - start the locate NIC feature of the elected adapter 
417  *
418  * Description:
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
421  *      be identified.
422  *
423  * Returns:     
424  *      ==0:    everything fine, no error, locateNIC test was started
425  *      !=0:    one locateNIC test runs already
426  *
427  */
428 static int locateDevice(struct net_device *dev, u32 data)
429 {
430         DEV_NET *pNet = netdev_priv(dev);
431         SK_AC *pAC = pNet->pAC;
432
433         if(!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
434                 data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
435
436         /* start blinking */
437         pAC->LedsOn = 0;
438         mod_timer(&pAC->BlinkTimer, jiffies);
439         msleep_interruptible(data * 1000);
440         del_timer_sync(&pAC->BlinkTimer);
441         toggleLeds(pNet, 0);
442
443         return 0;
444 }
445
446 /*****************************************************************************
447  *
448  *      getPauseParams - retrieves the pause parameters
449  *
450  * Description:
451  *      All current pause parameters of a selected adapter are placed 
452  *      in the passed ethtool_pauseparam structure and are returned.
453  *
454  * Returns:     N/A
455  *
456  */
457 static void getPauseParams(struct net_device *dev, struct ethtool_pauseparam *epause) 
458 {
459         DEV_NET *pNet = netdev_priv(dev);
460         SK_AC *pAC = pNet->pAC;
461         SK_GEPORT *pPort = &pAC->GIni.GP[pNet->PortNr];
462
463         epause->rx_pause = (pPort->PFlowCtrlMode == SK_FLOW_MODE_SYMMETRIC) ||
464                   (pPort->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM);
465
466         epause->tx_pause = epause->rx_pause || (pPort->PFlowCtrlMode == SK_FLOW_MODE_LOC_SEND);
467         epause->autoneg = epause->rx_pause || epause->tx_pause;
468 }
469
470 /*****************************************************************************
471  *
472  *      setPauseParams - configures the pause parameters of an adapter
473  *
474  * Description:
475  *      This function sets the Rx or Tx pause parameters 
476  *
477  * Returns:
478  *      ==0:    everything fine, no error
479  *      !=0:    the return value is the error code of the failure 
480  */
481 static int setPauseParams(struct net_device *dev , struct ethtool_pauseparam *epause)
482 {
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;
489         char    buf[4];
490         int     len = 1;
491         int ret;
492
493         /*
494         ** we have to determine the current settings to see if 
495         ** the operator requested any modification of the flow 
496         ** control parameters...
497         */
498         getPauseParams(dev, &old);
499
500         /*
501         ** perform modifications regarding the changes 
502         ** requested by the operator
503         */
504         if (epause->autoneg != old.autoneg) 
505                 *buf = epause->autoneg ? SK_FLOW_MODE_NONE : SK_FLOW_MODE_SYMMETRIC;
506         else {
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;
513                 else
514                         *buf = SK_FLOW_MODE_NONE;
515         }
516
517         ret = SkPnmiSetVar(pAC, pAC->IoBase, OID_SKGE_FLOWCTRL_MODE,
518                          &buf, &len, instance, pNet->NetNr);
519
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));
523                 goto err;
524         }
525
526         /*
527         ** It may be that autoneg has been disabled! Therefore
528         ** set the speed to the previously used value...
529         */
530         if (!epause->autoneg) {
531                 len = 1;
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));
537         }
538  err:
539         return ret ? -EIO : 0;
540 }
541
542 /* Only Yukon supports checksum offload. */
543 static int setScatterGather(struct net_device *dev, u32 data)
544 {
545         DEV_NET *pNet = netdev_priv(dev);
546         SK_AC *pAC = pNet->pAC;
547
548         if (pAC->GIni.GIChipId == CHIP_ID_GENESIS)
549                 return -EOPNOTSUPP;
550         return ethtool_op_set_sg(dev, data);
551 }
552
553 static int setTxCsum(struct net_device *dev, u32 data)
554 {
555         DEV_NET *pNet = netdev_priv(dev);
556         SK_AC *pAC = pNet->pAC;
557
558         if (pAC->GIni.GIChipId == CHIP_ID_GENESIS)
559                 return -EOPNOTSUPP;
560
561         return ethtool_op_set_tx_csum(dev, data);
562 }
563
564 static u32 getRxCsum(struct net_device *dev)
565 {
566         DEV_NET *pNet = netdev_priv(dev);
567         SK_AC *pAC = pNet->pAC;
568
569         return pAC->RxPort[pNet->PortNr].RxCsum;
570 }
571
572 static int setRxCsum(struct net_device *dev, u32 data)
573 {
574         DEV_NET *pNet = netdev_priv(dev);
575         SK_AC *pAC = pNet->pAC;
576
577         if (pAC->GIni.GIChipId == CHIP_ID_GENESIS)
578                 return -EOPNOTSUPP;
579
580         pAC->RxPort[pNet->PortNr].RxCsum = data != 0;
581         return 0;
582 }
583
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,
602 };