patch-2.4.21 linux-2.4.21/drivers/net/e1000/e1000_ethtool.c
Next file: linux-2.4.21/drivers/net/e1000/e1000_hw.c
Previous file: linux-2.4.21/drivers/net/e1000/e1000.h
Back to the patch index
Back to the overall index
- Lines: 380
- Date:
2003-06-13 07:51:34.000000000 -0700
- Orig file:
linux-2.4.20/drivers/net/e1000/e1000_ethtool.c
- Orig date:
2002-11-28 15:53:13.000000000 -0800
diff -urN linux-2.4.20/drivers/net/e1000/e1000_ethtool.c linux-2.4.21/drivers/net/e1000/e1000_ethtool.c
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
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
@@ -38,6 +38,17 @@
extern int e1000_up(struct e1000_adapter *adapter);
extern void e1000_down(struct e1000_adapter *adapter);
extern void e1000_reset(struct e1000_adapter *adapter);
+extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx);
+
+static char e1000_gstrings_stats[][ETH_GSTRING_LEN] = {
+ "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
+ "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
+ "rx_length_errors", "rx_over_errors", "rx_crc_errors",
+ "rx_frame_errors", "rx_fifo_errors", "rx_missed_errors",
+ "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
+ "tx_heartbeat_errors", "tx_window_errors",
+};
+#define E1000_STATS_LEN sizeof(e1000_gstrings_stats) / ETH_GSTRING_LEN
static void
e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
@@ -119,30 +130,9 @@
hw->autoneg = 1;
hw->autoneg_advertised = 0x002F;
ecmd->advertising = 0x002F;
- } else {
- hw->autoneg = 0;
- switch(ecmd->speed + ecmd->duplex) {
- case SPEED_10 + DUPLEX_HALF:
- hw->forced_speed_duplex = e1000_10_half;
- break;
- case SPEED_10 + DUPLEX_FULL:
- hw->forced_speed_duplex = e1000_10_full;
- break;
- case SPEED_100 + DUPLEX_HALF:
- hw->forced_speed_duplex = e1000_100_half;
- break;
- case SPEED_100 + DUPLEX_FULL:
- hw->forced_speed_duplex = e1000_100_full;
- break;
- case SPEED_1000 + DUPLEX_FULL:
- hw->autoneg = 1;
- hw->autoneg_advertised = ADVERTISE_1000_FULL;
- break;
- case SPEED_1000 + DUPLEX_HALF: /* not supported */
- default:
+ } else
+ if(e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex))
return -EINVAL;
- }
- }
/* reset the link */
@@ -155,16 +145,6 @@
return 0;
}
-static inline int
-e1000_eeprom_size(struct e1000_hw *hw)
-{
- if((hw->mac_type > e1000_82544) &&
- (E1000_READ_REG(hw, EECD) & E1000_EECD_SIZE))
- return 512;
- else
- return 128;
-}
-
static void
e1000_ethtool_gdrvinfo(struct e1000_adapter *adapter,
struct ethtool_drvinfo *drvinfo)
@@ -173,9 +153,10 @@
strncpy(drvinfo->version, e1000_driver_version, 32);
strncpy(drvinfo->fw_version, "N/A", 32);
strncpy(drvinfo->bus_info, adapter->pdev->slot_name, 32);
+ drvinfo->n_stats = E1000_STATS_LEN;
#define E1000_REGS_LEN 32
drvinfo->regdump_len = E1000_REGS_LEN * sizeof(uint32_t);
- drvinfo->eedump_len = e1000_eeprom_size(&adapter->hw);
+ drvinfo->eedump_len = adapter->hw.eeprom.word_size * 2;
}
static void
@@ -194,7 +175,7 @@
regs_buff[4] = E1000_READ_REG(hw, RDH);
regs_buff[5] = E1000_READ_REG(hw, RDT);
regs_buff[6] = E1000_READ_REG(hw, RDTR);
-
+
regs_buff[7] = E1000_READ_REG(hw, TCTL);
regs_buff[8] = E1000_READ_REG(hw, TDLEN);
regs_buff[9] = E1000_READ_REG(hw, TDH);
@@ -209,38 +190,50 @@
struct ethtool_eeprom *eeprom, uint16_t *eeprom_buff)
{
struct e1000_hw *hw = &adapter->hw;
- int i, max_len, first_word, last_word;
+ int first_word, last_word;
+ int ret_val = 0;
- if(eeprom->len == 0)
- return -EINVAL;
+ if(eeprom->len == 0) {
+ ret_val = -EINVAL;
+ goto geeprom_error;
+ }
eeprom->magic = hw->vendor_id | (hw->device_id << 16);
- max_len = e1000_eeprom_size(hw);
+ if(eeprom->offset > eeprom->offset + eeprom->len) {
+ ret_val = -EINVAL;
+ goto geeprom_error;
+ }
- if(eeprom->offset > eeprom->offset + eeprom->len)
- return -EINVAL;
-
- if((eeprom->offset + eeprom->len) > max_len)
- eeprom->len = (max_len - eeprom->offset);
+ if((eeprom->offset + eeprom->len) > (hw->eeprom.word_size * 2))
+ eeprom->len = ((hw->eeprom.word_size * 2) - eeprom->offset);
first_word = eeprom->offset >> 1;
last_word = (eeprom->offset + eeprom->len - 1) >> 1;
- for(i = 0; i <= (last_word - first_word); i++)
- e1000_read_eeprom(hw, first_word + i, &eeprom_buff[i]);
-
- return 0;
+ if(hw->eeprom.type == e1000_eeprom_spi)
+ ret_val = e1000_read_eeprom(hw, first_word,
+ last_word - first_word + 1,
+ eeprom_buff);
+ else {
+ uint16_t i;
+ for (i = 0; i < last_word - first_word + 1; i++)
+ if((ret_val = e1000_read_eeprom(hw, first_word + i, 1,
+ &eeprom_buff[i])))
+ break;
+ }
+geeprom_error:
+ return ret_val;
}
-static int
+static int
e1000_ethtool_seeprom(struct e1000_adapter *adapter,
struct ethtool_eeprom *eeprom, void *user_data)
{
struct e1000_hw *hw = &adapter->hw;
- uint16_t eeprom_buff[256];
- int i, max_len, first_word, last_word;
+ uint16_t *eeprom_buff;
void *ptr;
+ int max_len, first_word, last_word, ret_val = 0;
if(eeprom->len == 0)
return -EOPNOTSUPP;
@@ -248,38 +241,47 @@
if(eeprom->magic != (hw->vendor_id | (hw->device_id << 16)))
return -EFAULT;
- max_len = e1000_eeprom_size(hw);
+ max_len = hw->eeprom.word_size * 2;
if((eeprom->offset + eeprom->len) > max_len)
eeprom->len = (max_len - eeprom->offset);
first_word = eeprom->offset >> 1;
last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+ eeprom_buff = kmalloc(max_len, GFP_KERNEL);
+ if(eeprom_buff == NULL)
+ return -ENOMEM;
+
ptr = (void *)eeprom_buff;
if(eeprom->offset & 1) {
/* need read/modify/write of first changed EEPROM word */
/* only the second byte of the word is being modified */
- e1000_read_eeprom(hw, first_word, &eeprom_buff[0]);
+ ret_val = e1000_read_eeprom(hw, first_word, 1,
+ &eeprom_buff[0]);
ptr++;
}
- if((eeprom->offset + eeprom->len) & 1) {
+ if(((eeprom->offset + eeprom->len) & 1) && (ret_val == 0)) {
/* need read/modify/write of last changed EEPROM word */
/* only the first byte of the word is being modified */
- e1000_read_eeprom(hw, last_word,
+ ret_val = e1000_read_eeprom(hw, last_word, 1,
&eeprom_buff[last_word - first_word]);
}
- if(copy_from_user(ptr, user_data, eeprom->len))
- return -EFAULT;
+ if((ret_val != 0) || copy_from_user(ptr, user_data, eeprom->len)) {
+ ret_val = -EFAULT;
+ goto seeprom_error;
+ }
- for(i = 0; i <= (last_word - first_word); i++)
- e1000_write_eeprom(hw, first_word + i, eeprom_buff[i]);
+ ret_val = e1000_write_eeprom(hw, first_word,
+ last_word - first_word + 1, eeprom_buff);
/* Update the checksum over the first part of the EEPROM if needed */
- if(first_word <= EEPROM_CHECKSUM_REG)
+ if((ret_val == 0) && first_word <= EEPROM_CHECKSUM_REG)
e1000_update_eeprom_checksum(hw);
- return 0;
+seeprom_error:
+ kfree(eeprom_buff);
+ return ret_val;
}
static void
@@ -306,12 +308,10 @@
/* Fall Through */
default:
- wol->supported = WAKE_PHY | WAKE_UCAST |
- WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC;
-
+ wol->supported = WAKE_UCAST | WAKE_MCAST |
+ WAKE_BCAST | WAKE_MAGIC;
+
wol->wolopts = 0;
- if(adapter->wol & E1000_WUFC_LNKC)
- wol->wolopts |= WAKE_PHY;
if(adapter->wol & E1000_WUFC_EX)
wol->wolopts |= WAKE_UCAST;
if(adapter->wol & E1000_WUFC_MC)
@@ -343,13 +343,11 @@
/* Fall Through */
default:
- if(wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE))
+ if(wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
return -EOPNOTSUPP;
adapter->wol = 0;
- if(wol->wolopts & WAKE_PHY)
- adapter->wol |= E1000_WUFC_LNKC;
if(wol->wolopts & WAKE_UCAST)
adapter->wol |= E1000_WUFC_EX;
if(wol->wolopts & WAKE_MCAST)
@@ -374,7 +372,7 @@
e1000_led_blink_callback(unsigned long data)
{
struct e1000_adapter *adapter = (struct e1000_adapter *) data;
-
+
if(test_and_change_bit(E1000_LED_ON, &adapter->led_status))
e1000_led_off(&adapter->hw);
else
@@ -394,13 +392,13 @@
e1000_setup_led(&adapter->hw);
mod_timer(&adapter->blink_timer, jiffies);
-
+
set_current_state(TASK_INTERRUPTIBLE);
if(id->data)
schedule_timeout(id->data * HZ);
else
schedule_timeout(MAX_SCHEDULE_TIMEOUT);
-
+
del_timer_sync(&adapter->blink_timer);
e1000_led_off(&adapter->hw);
clear_bit(E1000_LED_ON, &adapter->led_status);
@@ -442,6 +440,28 @@
return -EFAULT;
return 0;
}
+ case ETHTOOL_GSTRINGS: {
+ struct ethtool_gstrings gstrings = { ETHTOOL_GSTRINGS };
+ char *strings = NULL;
+
+ if(copy_from_user(&gstrings, addr, sizeof(gstrings)))
+ return -EFAULT;
+ switch(gstrings.string_set) {
+ case ETH_SS_STATS:
+ gstrings.len = E1000_STATS_LEN;
+ strings = *e1000_gstrings_stats;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ if(copy_to_user(addr, &gstrings, sizeof(gstrings)))
+ return -EFAULT;
+ addr += offsetof(struct ethtool_gstrings, data);
+ if(copy_to_user(addr, strings,
+ gstrings.len * ETH_GSTRING_LEN))
+ return -EFAULT;
+ return 0;
+ }
case ETHTOOL_GREGS: {
struct ethtool_regs regs = {ETHTOOL_GREGS};
uint32_t regs_buff[E1000_REGS_LEN];
@@ -497,26 +517,39 @@
}
case ETHTOOL_GEEPROM: {
struct ethtool_eeprom eeprom = {ETHTOOL_GEEPROM};
- uint16_t eeprom_buff[256];
+ struct e1000_hw *hw = &adapter->hw;
+ uint16_t *eeprom_buff;
void *ptr;
- int err;
+ int err = 0;
- if(copy_from_user(&eeprom, addr, sizeof(eeprom)))
- return -EFAULT;
+ eeprom_buff = kmalloc(hw->eeprom.word_size * 2, GFP_KERNEL);
- if((err = e1000_ethtool_geeprom(adapter,
- &eeprom, eeprom_buff)))
- return err;
+ if(eeprom_buff == NULL)
+ return -ENOMEM;
- if(copy_to_user(addr, &eeprom, sizeof(eeprom)))
- return -EFAULT;
+ if(copy_from_user(&eeprom, addr, sizeof(eeprom))) {
+ err = -EFAULT;
+ goto err_geeprom_ioctl;
+ }
+
+ if((err = e1000_ethtool_geeprom(adapter, &eeprom,
+ eeprom_buff)))
+ goto err_geeprom_ioctl;
+
+ if(copy_to_user(addr, &eeprom, sizeof(eeprom))) {
+ err = -EFAULT;
+ goto err_geeprom_ioctl;
+ }
addr += offsetof(struct ethtool_eeprom, data);
ptr = ((void *)eeprom_buff) + (eeprom.offset & 1);
if(copy_to_user(addr, ptr, eeprom.len))
- return -EFAULT;
- return 0;
+ err = -EFAULT;
+
+err_geeprom_ioctl:
+ kfree(eeprom_buff);
+ return err;
}
case ETHTOOL_SEEPROM: {
struct ethtool_eeprom eeprom;
@@ -530,6 +563,20 @@
addr += offsetof(struct ethtool_eeprom, data);
return e1000_ethtool_seeprom(adapter, &eeprom, addr);
}
+ case ETHTOOL_GSTATS: {
+ struct {
+ struct ethtool_stats cmd;
+ uint64_t data[E1000_STATS_LEN];
+ } stats = { {ETHTOOL_GSTATS, E1000_STATS_LEN} };
+ int i;
+
+ for(i = 0; i < E1000_STATS_LEN; i++)
+ stats.data[i] =
+ ((unsigned long *)&adapter->net_stats)[i];
+ if(copy_to_user(addr, &stats, sizeof(stats)))
+ return -EFAULT;
+ return 0;
+ }
default:
return -EOPNOTSUPP;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)