ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / net / ixgb / ixgb_ethtool.c
1 /*******************************************************************************
2
3   
4   Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
5   
6   This program is free software; you can redistribute it and/or modify it 
7   under the terms of the GNU General Public License as published by the Free 
8   Software Foundation; either version 2 of the License, or (at your option) 
9   any later version.
10   
11   This program is distributed in the hope that it will be useful, but WITHOUT 
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
14   more details.
15   
16   You should have received a copy of the GNU General Public License along with
17   this program; if not, write to the Free Software Foundation, Inc., 59 
18   Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19   
20   The full GNU General Public License is included in this distribution in the
21   file called LICENSE.
22   
23   Contact Information:
24   Linux NICS <linux.nics@intel.com>
25   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
26 *******************************************************************************/
27
28 /* ethtool support for ixgb */
29
30 #include "ixgb.h"
31
32 #include <asm/uaccess.h>
33
34 extern char ixgb_driver_name[];
35 extern char ixgb_driver_version[];
36
37 extern int ixgb_up(struct ixgb_adapter *adapter);
38 extern int ixgb_down(struct ixgb_adapter *adapter);
39
40 /**
41  * ixgb_ethtool_ioctl - Ethtool Ioctl Support
42  * @netdev: net device structure
43  * @ifr: interface request structure
44  **/
45
46 static inline int
47 ixgb_eeprom_size(struct ixgb_hw *hw)
48 {
49         /* return size in bytes */
50         return (IXGB_EEPROM_SIZE << 1);
51 }
52
53 #define SPEED_10000 10000
54
55 static void
56 ixgb_ethtool_gset(struct ixgb_adapter *adapter, struct ethtool_cmd *ecmd)
57 {
58         ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
59         ecmd->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
60         ecmd->port = PORT_FIBRE;
61         ecmd->transceiver = XCVR_EXTERNAL;
62
63         if (netif_carrier_ok(adapter->netdev)) {
64                 ecmd->speed = 10000;
65                 ecmd->duplex = DUPLEX_FULL;
66         } else {
67                 ecmd->speed = -1;
68                 ecmd->duplex = -1;
69         }
70
71         ecmd->autoneg = AUTONEG_DISABLE;
72 }
73
74 static int
75 ixgb_ethtool_sset(struct ixgb_adapter *adapter, struct ethtool_cmd *ecmd)
76 {
77         if (ecmd->autoneg == AUTONEG_ENABLE ||
78             ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)
79                 return -EINVAL;
80         else {
81                 ixgb_down(adapter);
82                 ixgb_up(adapter);
83         }
84
85         return 0;
86 }
87
88 #if 0
89 static int
90 ixgb_ethtool_promiscuous(struct ixgb_adapter *adapter,
91                          struct ethtool_pmode *pmode)
92 {
93         u32 rctl = IXGB_READ_REG(&adapter->hw, RCTL);
94
95         pmode->rctl_old = rctl;
96         if (pmode->upe)
97                 rctl |= IXGB_RCTL_UPE;
98         else
99                 rctl &= ~IXGB_RCTL_UPE;
100
101         if (pmode->mpe)
102                 rctl |= IXGB_RCTL_MPE;
103         else
104                 rctl &= ~IXGB_RCTL_MPE;
105
106         IXGB_WRITE_REG(&adapter->hw, RCTL, rctl);
107
108         pmode->rctl_new = IXGB_READ_REG(&adapter->hw, RCTL);
109
110         return 0;
111 }
112 #endif
113
114 #define IXGB_REG_DUMP_LEN  136*sizeof(u32)
115 static void
116 ixgb_ethtool_gdrvinfo(struct ixgb_adapter *adapter,
117                       struct ethtool_drvinfo *drvinfo)
118 {
119         strncpy(drvinfo->driver, ixgb_driver_name, 32);
120         strncpy(drvinfo->version, ixgb_driver_version, 32);
121         strncpy(drvinfo->fw_version, "", 32);
122         strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
123 #ifdef ETHTOOL_GREGS
124         drvinfo->regdump_len = IXGB_REG_DUMP_LEN;
125 #endif                          /* ETHTOOL_GREGS */
126         drvinfo->eedump_len = ixgb_eeprom_size(&adapter->hw);
127 }
128
129 #ifdef  ETHTOOL_GREGS
130 #define IXGB_GET_STAT(_A_, _R_) _A_->stats._R_
131 static void
132 ixgb_ethtool_gregs(struct ixgb_adapter *adapter,
133                    struct ethtool_regs *regs, u8 * regs_buff)
134 {
135         struct ixgb_hw *hw = &adapter->hw;
136         u32 *reg = (u32 *) regs_buff;
137         u32 *reg_start = reg;
138         u8 i;
139
140         regs->version =
141             (adapter->hw.device_id << 16) | adapter->hw.subsystem_id;
142
143         /* General Registers */
144         *reg++ = IXGB_READ_REG(hw, CTRL0);      /*   0 */
145         *reg++ = IXGB_READ_REG(hw, CTRL1);      /*   1 */
146         *reg++ = IXGB_READ_REG(hw, STATUS);     /*   2 */
147         *reg++ = IXGB_READ_REG(hw, EECD);       /*   3 */
148         *reg++ = IXGB_READ_REG(hw, MFS);        /*   4 */
149
150         /* Interrupt */
151         *reg++ = IXGB_READ_REG(hw, ICR);        /*   5 */
152         *reg++ = IXGB_READ_REG(hw, ICS);        /*   6 */
153         *reg++ = IXGB_READ_REG(hw, IMS);        /*   7 */
154         *reg++ = IXGB_READ_REG(hw, IMC);        /*   8 */
155
156         /* Receive */
157         *reg++ = IXGB_READ_REG(hw, RCTL);       /*   9 */
158         *reg++ = IXGB_READ_REG(hw, FCRTL);      /*  10 */
159         *reg++ = IXGB_READ_REG(hw, FCRTH);      /*  11 */
160         *reg++ = IXGB_READ_REG(hw, RDBAL);      /*  12 */
161         *reg++ = IXGB_READ_REG(hw, RDBAH);      /*  13 */
162         *reg++ = IXGB_READ_REG(hw, RDLEN);      /*  14 */
163         *reg++ = IXGB_READ_REG(hw, RDH);        /*  15 */
164         *reg++ = IXGB_READ_REG(hw, RDT);        /*  16 */
165         *reg++ = IXGB_READ_REG(hw, RDTR);       /*  17 */
166         *reg++ = IXGB_READ_REG(hw, RXDCTL);     /*  18 */
167         *reg++ = IXGB_READ_REG(hw, RAIDC);      /*  19 */
168         *reg++ = IXGB_READ_REG(hw, RXCSUM);     /*  20 */
169
170         for (i = 0; i < IXGB_RAR_ENTRIES; i++) {
171                 *reg++ = IXGB_READ_REG_ARRAY(hw, RAL, (i << 1));        /*21,...,51 */
172                 *reg++ = IXGB_READ_REG_ARRAY(hw, RAH, (i << 1));        /*22,...,52 */
173         }
174
175         /* Transmit */
176         *reg++ = IXGB_READ_REG(hw, TCTL);       /*  53 */
177         *reg++ = IXGB_READ_REG(hw, TDBAL);      /*  54 */
178         *reg++ = IXGB_READ_REG(hw, TDBAH);      /*  55 */
179         *reg++ = IXGB_READ_REG(hw, TDLEN);      /*  56 */
180         *reg++ = IXGB_READ_REG(hw, TDH);        /*  57 */
181         *reg++ = IXGB_READ_REG(hw, TDT);        /*  58 */
182         *reg++ = IXGB_READ_REG(hw, TIDV);       /*  59 */
183         *reg++ = IXGB_READ_REG(hw, TXDCTL);     /*  60 */
184         *reg++ = IXGB_READ_REG(hw, TSPMT);      /*  61 */
185         *reg++ = IXGB_READ_REG(hw, PAP);        /*  62 */
186
187         /* Physical */
188         *reg++ = IXGB_READ_REG(hw, PCSC1);      /*  63 */
189         *reg++ = IXGB_READ_REG(hw, PCSC2);      /*  64 */
190         *reg++ = IXGB_READ_REG(hw, PCSS1);      /*  65 */
191         *reg++ = IXGB_READ_REG(hw, PCSS2);      /*  66 */
192         *reg++ = IXGB_READ_REG(hw, XPCSS);      /*  67 */
193         *reg++ = IXGB_READ_REG(hw, UCCR);       /*  68 */
194         *reg++ = IXGB_READ_REG(hw, XPCSTC);     /*  69 */
195         *reg++ = IXGB_READ_REG(hw, MACA);       /*  70 */
196         *reg++ = IXGB_READ_REG(hw, APAE);       /*  71 */
197         *reg++ = IXGB_READ_REG(hw, ARD);        /*  72 */
198         *reg++ = IXGB_READ_REG(hw, AIS);        /*  73 */
199         *reg++ = IXGB_READ_REG(hw, MSCA);       /*  74 */
200         *reg++ = IXGB_READ_REG(hw, MSRWD);      /*  75 */
201
202 #if 0
203         /* Wake-up */
204         reg[IXGB_WUFC] = IXGB_READ_REG(hw, WUFC);
205         reg[IXGB_WUS] = IXGB_READ_REG(hw, WUS);
206         reg[IXGB_FFLT] = IXGB_READ_REG(hw, FFLT);
207         reg[IXGB_FFMT] = IXGB_READ_REG(hw, FFMT);
208         reg[IXGB_FTVT] = IXGB_READ_REG(hw, FTVT);
209 #endif
210
211         /* Statistics */
212         *reg++ = IXGB_GET_STAT(adapter, tprl);  /*  76 */
213         *reg++ = IXGB_GET_STAT(adapter, tprh);  /*  77 */
214         *reg++ = IXGB_GET_STAT(adapter, gprcl); /*  78 */
215         *reg++ = IXGB_GET_STAT(adapter, gprch); /*  79 */
216         *reg++ = IXGB_GET_STAT(adapter, bprcl); /*  80 */
217         *reg++ = IXGB_GET_STAT(adapter, bprch); /*  81 */
218         *reg++ = IXGB_GET_STAT(adapter, mprcl); /*  82 */
219         *reg++ = IXGB_GET_STAT(adapter, mprch); /*  83 */
220         *reg++ = IXGB_GET_STAT(adapter, uprcl); /*  84 */
221         *reg++ = IXGB_GET_STAT(adapter, uprch); /*  85 */
222         *reg++ = IXGB_GET_STAT(adapter, vprcl); /*  86 */
223         *reg++ = IXGB_GET_STAT(adapter, vprch); /*  87 */
224         *reg++ = IXGB_GET_STAT(adapter, jprcl); /*  88 */
225         *reg++ = IXGB_GET_STAT(adapter, jprch); /*  89 */
226         *reg++ = IXGB_GET_STAT(adapter, gorcl); /*  90 */
227         *reg++ = IXGB_GET_STAT(adapter, gorch); /*  91 */
228         *reg++ = IXGB_GET_STAT(adapter, torl);  /*  92 */
229         *reg++ = IXGB_GET_STAT(adapter, torh);  /*  93 */
230         *reg++ = IXGB_GET_STAT(adapter, rnbc);  /*  94 */
231         *reg++ = IXGB_GET_STAT(adapter, ruc);   /*  95 */
232         *reg++ = IXGB_GET_STAT(adapter, roc);   /*  96 */
233         *reg++ = IXGB_GET_STAT(adapter, rlec);  /*  97 */
234         *reg++ = IXGB_GET_STAT(adapter, crcerrs);       /*  98 */
235         *reg++ = IXGB_GET_STAT(adapter, icbc);  /*  99 */
236         *reg++ = IXGB_GET_STAT(adapter, ecbc);  /* 100 */
237         *reg++ = IXGB_GET_STAT(adapter, mpc);   /* 101 */
238         *reg++ = IXGB_GET_STAT(adapter, tptl);  /* 102 */
239         *reg++ = IXGB_GET_STAT(adapter, tpth);  /* 103 */
240         *reg++ = IXGB_GET_STAT(adapter, gptcl); /* 104 */
241         *reg++ = IXGB_GET_STAT(adapter, gptch); /* 105 */
242         *reg++ = IXGB_GET_STAT(adapter, bptcl); /* 106 */
243         *reg++ = IXGB_GET_STAT(adapter, bptch); /* 107 */
244         *reg++ = IXGB_GET_STAT(adapter, mptcl); /* 108 */
245         *reg++ = IXGB_GET_STAT(adapter, mptch); /* 109 */
246         *reg++ = IXGB_GET_STAT(adapter, uptcl); /* 110 */
247         *reg++ = IXGB_GET_STAT(adapter, uptch); /* 111 */
248         *reg++ = IXGB_GET_STAT(adapter, vptcl); /* 112 */
249         *reg++ = IXGB_GET_STAT(adapter, vptch); /* 113 */
250         *reg++ = IXGB_GET_STAT(adapter, jptcl); /* 114 */
251         *reg++ = IXGB_GET_STAT(adapter, jptch); /* 115 */
252         *reg++ = IXGB_GET_STAT(adapter, gotcl); /* 116 */
253         *reg++ = IXGB_GET_STAT(adapter, gotch); /* 117 */
254         *reg++ = IXGB_GET_STAT(adapter, totl);  /* 118 */
255         *reg++ = IXGB_GET_STAT(adapter, toth);  /* 119 */
256         *reg++ = IXGB_GET_STAT(adapter, dc);    /* 120 */
257         *reg++ = IXGB_GET_STAT(adapter, plt64c);        /* 121 */
258         *reg++ = IXGB_GET_STAT(adapter, tsctc); /* 122 */
259         *reg++ = IXGB_GET_STAT(adapter, tsctfc);        /* 123 */
260         *reg++ = IXGB_GET_STAT(adapter, ibic);  /* 124 */
261         *reg++ = IXGB_GET_STAT(adapter, rfc);   /* 125 */
262         *reg++ = IXGB_GET_STAT(adapter, lfc);   /* 126 */
263         *reg++ = IXGB_GET_STAT(adapter, pfrc);  /* 127 */
264         *reg++ = IXGB_GET_STAT(adapter, pftc);  /* 128 */
265         *reg++ = IXGB_GET_STAT(adapter, mcfrc); /* 129 */
266         *reg++ = IXGB_GET_STAT(adapter, mcftc); /* 130 */
267         *reg++ = IXGB_GET_STAT(adapter, xonrxc);        /* 131 */
268         *reg++ = IXGB_GET_STAT(adapter, xontxc);        /* 132 */
269         *reg++ = IXGB_GET_STAT(adapter, xoffrxc);       /* 133 */
270         *reg++ = IXGB_GET_STAT(adapter, xofftxc);       /* 134 */
271         *reg++ = IXGB_GET_STAT(adapter, rjc);   /* 135 */
272
273 #if 0
274 #endif
275         regs->len = (reg - reg_start) * sizeof (u32);
276 }
277 #endif                          /* ETHTOOL_GREGS */
278
279 static int
280 ixgb_ethtool_geeprom(struct ixgb_adapter *adapter,
281                      struct ethtool_eeprom *eeprom, u16 * eeprom_buff)
282 {
283         struct ixgb_hw *hw = &adapter->hw;
284         int i, max_len, first_word, last_word;
285         IXGB_DBG("ixgb_ethtool_geeprom\n");
286
287         if (eeprom->len == 0)
288                 return -EINVAL;
289
290         eeprom->magic = hw->vendor_id | (hw->device_id << 16);
291
292         max_len = ixgb_eeprom_size(hw);
293
294         /* use our function to read the eeprom and update our cache */
295         ixgb_get_eeprom_data(hw);
296
297         if (eeprom->offset > eeprom->offset + eeprom->len)
298                 return -EINVAL;
299
300         if ((eeprom->offset + eeprom->len) > max_len)
301                 eeprom->len = (max_len - eeprom->offset);
302
303         first_word = eeprom->offset >> 1;
304         last_word = (eeprom->offset + eeprom->len - 1) >> 1;
305
306         for (i = 0; i <= (last_word - first_word); i++) {
307                 eeprom_buff[i] = hw->eeprom[first_word + i];
308         }
309
310         return 0;
311 }
312 static int
313 ixgb_ethtool_seeprom(struct ixgb_adapter *adapter,
314                      struct ethtool_eeprom *eeprom, void *user_data)
315 {
316         struct ixgb_hw *hw = &adapter->hw;
317         u16 eeprom_buff[256];
318         int i, max_len, first_word, last_word;
319         void *ptr;
320
321         if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16)))
322                 return -EFAULT;
323
324         if (eeprom->len == 0)
325                 return -EINVAL;
326
327         max_len = ixgb_eeprom_size(hw);
328
329         if (eeprom->offset > eeprom->offset + eeprom->len)
330                 return -EINVAL;
331
332         if ((eeprom->offset + eeprom->len) > max_len)
333                 eeprom->len = (max_len - eeprom->offset);
334
335         first_word = eeprom->offset >> 1;
336         last_word = (eeprom->offset + eeprom->len - 1) >> 1;
337         ptr = (void *) eeprom_buff;
338
339         if (eeprom->offset & 1) {
340                 /* need read/modify/write of first changed EEPROM word */
341                 /* only the second byte of the word is being modified */
342                 eeprom_buff[0] = ixgb_read_eeprom(hw, first_word);
343                 ptr++;
344         }
345         if ((eeprom->offset + eeprom->len) & 1) {
346                 /* need read/modify/write of last changed EEPROM word */
347                 /* only the first byte of the word is being modified */
348                 eeprom_buff[last_word - first_word]
349                     = ixgb_read_eeprom(hw, last_word);
350         }
351         if (copy_from_user(ptr, user_data, eeprom->len))
352                 return -EFAULT;
353
354         for (i = 0; i <= (last_word - first_word); i++)
355                 ixgb_write_eeprom(hw, first_word + i, eeprom_buff[i]);
356
357         /* Update the checksum over the first part of the EEPROM if needed */
358         if (first_word <= EEPROM_CHECKSUM_REG)
359                 ixgb_update_eeprom_checksum(hw);
360
361         return 0;
362 }
363
364 #ifdef  ETHTOOL_PHYS_ID
365
366 /* toggle LED 4 times per second = 2 "blinks" per second */
367 #define IXGB_ID_INTERVAL    (HZ/4)
368
369 /* bit defines for adapter->led_status */
370 #define IXGB_LED_ON     0
371
372 static void
373 ixgb_led_blink_callback(unsigned long data)
374 {
375         struct ixgb_adapter *adapter = (struct ixgb_adapter *) data;
376
377         if (test_and_change_bit(IXGB_LED_ON, &adapter->led_status))
378                 ixgb_led_off(&adapter->hw);
379         else
380                 ixgb_led_on(&adapter->hw);
381
382         mod_timer(&adapter->blink_timer, jiffies + IXGB_ID_INTERVAL);
383 }
384
385 static int
386 ixgb_ethtool_led_blink(struct ixgb_adapter *adapter, struct ethtool_value *id)
387 {
388         if (!adapter->blink_timer.function) {
389                 init_timer(&adapter->blink_timer);
390                 adapter->blink_timer.function = ixgb_led_blink_callback;
391                 adapter->blink_timer.data = (unsigned long) adapter;
392         }
393
394         mod_timer(&adapter->blink_timer, jiffies);
395
396         set_current_state(TASK_INTERRUPTIBLE);
397         if (id->data)
398                 schedule_timeout(id->data * HZ);
399         else
400                 schedule_timeout(MAX_SCHEDULE_TIMEOUT);
401
402         del_timer_sync(&adapter->blink_timer);
403         ixgb_led_off(&adapter->hw);
404         clear_bit(IXGB_LED_ON, &adapter->led_status);
405
406         return 0;
407 }
408 #endif                          /* ETHTOOL_PHYS_ID */
409
410 int
411 ixgb_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr)
412 {
413         struct ixgb_adapter *adapter = netdev->priv;
414         void *addr = ifr->ifr_data;
415         u32 cmd;
416
417         if (get_user(cmd, (u32 *) addr))
418                 return -EFAULT;
419
420         switch (cmd) {
421 #if 0
422         case ETHTOOL_PROMISCUOUS:{
423                         struct ethtool_pmode pmode;
424
425                         if (copy_from_user(&pmode, addr, sizeof (pmode)))
426                                 return -EFAULT;
427
428                         ixgb_ethtool_promiscuous(adapter, &pmode);
429
430                         if (copy_to_user(addr, &pmode, sizeof (pmode)))
431                                 return -EFAULT;
432
433                         return 0;
434                 }
435         case ETHTOOL_DOWN_UP:
436                 ixgb_down(netdev->priv);
437                 ixgb_up(netdev->priv);
438                 return 0;
439 #endif
440         case ETHTOOL_GSET:{
441                         struct ethtool_cmd ecmd = { ETHTOOL_GSET };
442
443                         ixgb_ethtool_gset(adapter, &ecmd);
444                         if (copy_to_user(addr, &ecmd, sizeof (ecmd)))
445                                 return -EFAULT;
446                         return 0;
447                 }
448         case ETHTOOL_SSET:{
449                         struct ethtool_cmd ecmd;
450
451                         if (copy_from_user(&ecmd, addr, sizeof (ecmd)))
452                                 return -EFAULT;
453                         return ixgb_ethtool_sset(adapter, &ecmd);
454                 }
455         case ETHTOOL_GDRVINFO:
456                 {
457                         struct ethtool_drvinfo drvinfo = { ETHTOOL_GDRVINFO };
458
459                         ixgb_ethtool_gdrvinfo(adapter, &drvinfo);
460                         if (copy_to_user(addr, &drvinfo, sizeof (drvinfo)))
461                                 return -EFAULT;
462                         return 0;
463                 }
464 #if defined(ETHTOOL_GREGS) && defined(ETHTOOL_GEEPROM)
465         case ETHTOOL_GREGS:{
466                         struct ethtool_regs regs = { ETHTOOL_GREGS };
467                         u8 regs_buff[IXGB_REG_DUMP_LEN];
468
469                         ixgb_ethtool_gregs(adapter, &regs, regs_buff);
470
471                         if (copy_to_user(addr, &regs, sizeof (regs)))
472                                 return -EFAULT;
473
474                         addr += offsetof(struct ethtool_regs, data);
475
476                         if (copy_to_user(addr, regs_buff, regs.len))
477                                 return -EFAULT;
478                         return 0;
479                 }
480 #endif                          /* ETHTOOL_GREGS */
481         case ETHTOOL_NWAY_RST:{
482                         IXGB_DBG("ETHTOOL_NWAY_RST\n");
483                         ixgb_down(adapter);
484                         ixgb_up(adapter);
485
486                         return 0;
487                 }
488 #ifdef  ETHTOOL_PHYS_ID
489         case ETHTOOL_PHYS_ID:{
490                         struct ethtool_value id;
491
492                         IXGB_DBG("ETHTOOL_PHYS_ID\n");
493                         if (copy_from_user(&id, addr, sizeof (id)))
494                                 return -EFAULT;
495                         return ixgb_ethtool_led_blink(adapter, &id);
496                 }
497 #endif                          /* ETHTOOL_PHYS_ID */
498         case ETHTOOL_GLINK:{
499                         struct ethtool_value link = { ETHTOOL_GLINK };
500
501                         IXGB_DBG("ETHTOOL_GLINK\n");
502                         link.data = netif_carrier_ok(netdev);
503                         if (copy_to_user(addr, &link, sizeof (link)))
504                                 return -EFAULT;
505                         return 0;
506                 }
507
508         case ETHTOOL_GEEPROM:{
509                         struct ethtool_eeprom eeprom = { ETHTOOL_GEEPROM };
510                         u16 eeprom_buff[IXGB_EEPROM_SIZE];
511                         void *ptr;
512                         int err;
513
514                         IXGB_DBG("ETHTOOL_GEEPROM\n");
515                         if (copy_from_user(&eeprom, addr, sizeof (eeprom)))
516                                 return -EFAULT;
517
518                         if ((err =
519                              ixgb_ethtool_geeprom(adapter, &eeprom,
520                                                   eeprom_buff)) < 0)
521                                 return err;
522
523                         if (copy_to_user(addr, &eeprom, sizeof (eeprom)))
524                                 return -EFAULT;
525
526                         addr += offsetof(struct ethtool_eeprom, data);
527
528                         ptr = ((void *) eeprom_buff) + (eeprom.offset & 1);
529                         if (copy_to_user(addr, ptr, eeprom.len))
530                                 return -EFAULT;
531                         return 0;
532                 }
533         case ETHTOOL_SEEPROM:{
534                         struct ethtool_eeprom eeprom;
535
536                         IXGB_DBG("ETHTOOL_SEEPROM\n");
537                         if (copy_from_user(&eeprom, addr, sizeof (eeprom)))
538                                 return -EFAULT;
539
540                         addr += offsetof(struct ethtool_eeprom, data);
541                         return ixgb_ethtool_seeprom(adapter, &eeprom, addr);
542                 }
543         default:
544                 return -EOPNOTSUPP;
545         }
546 }