Commit 8a76ddc0 authored by Scott Feldman's avatar Scott Feldman Committed by Jeff Garzik

e1000 net driver update 1/4:

* Adds support for ETHTOOL_GREGS to dump register set to ethtool. 
* Adds support for ETHTOOL_LEDBLINK to blink LED's on adapter 
  from ethtool. 
* Bug fix: error message added for corrupted EEPROM detection. 
* Bug fix: when setting up link on copper interface, explicitly 
  turn off force speed and duplex before auto-negotiation. 
parent a82fa3a4
......@@ -107,7 +107,6 @@
#include <linux/udp.h>
#include <net/pkt_sched.h>
#include <linux/list.h>
#include <asm/uaccess.h>
#include <linux/ethtool.h>
#ifdef NETIF_F_HW_VLAN_TX
#include <linux/if_vlan.h>
......@@ -204,6 +203,11 @@ struct e1000_adapter {
spinlock_t stats_lock;
atomic_t irq_sem;
#ifdef ETHTOOL_PHYS_ID
struct timer_list blink_timer;
unsigned long led_status;
#endif
/* TX */
struct e1000_desc_ring tx_ring;
unsigned long trans_finish;
......@@ -228,6 +232,7 @@ struct e1000_adapter {
struct e1000_hw_stats stats;
struct e1000_phy_info phy_info;
struct e1000_phy_stats phy_stats;
};
};
#endif /* _E1000_H_ */
......@@ -75,7 +75,6 @@
#include "e1000.h"
#include <linux/ethtool.h>
#include <asm/uaccess.h>
extern char e1000_driver_name[];
......@@ -211,9 +210,37 @@ e1000_ethtool_gdrvinfo(struct e1000_adapter *adapter,
strncpy(drvinfo->version, e1000_driver_version, 32);
strncpy(drvinfo->fw_version, "", 32);
strncpy(drvinfo->bus_info, adapter->pdev->slot_name, 32);
#define E1000_REGS_LEN 32
drvinfo->regdump_len = E1000_REGS_LEN * sizeof(uint32_t);
drvinfo->eedump_len = e1000_eeprom_size(&adapter->hw);
}
static void
e1000_ethtool_gregs(struct e1000_adapter *adapter,
struct ethtool_regs *regs, uint32_t *regs_buff)
{
struct e1000_hw *hw = &adapter->hw;
regs->version = (1 << 24) | (hw->revision_id << 16) | hw->device_id;
regs_buff[0] = E1000_READ_REG(hw, CTRL);
regs_buff[1] = E1000_READ_REG(hw, STATUS);
regs_buff[2] = E1000_READ_REG(hw, RCTL);
regs_buff[3] = E1000_READ_REG(hw, RDLEN);
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);
regs_buff[10] = E1000_READ_REG(hw, TDT);
regs_buff[11] = E1000_READ_REG(hw, TIDV);
return;
}
static void
e1000_ethtool_geeprom(struct e1000_adapter *adapter,
struct ethtool_eeprom *eeprom, uint16_t *eeprom_buff)
......@@ -284,6 +311,54 @@ e1000_ethtool_swol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol)
return 0;
}
#ifdef ETHTOOL_PHYS_ID
/* toggle LED 4 times per second = 2 "blinks" per second */
#define E1000_ID_INTERVAL (HZ/4)
/* bit defines for adapter->led_status */
#define E1000_LED_ON 0
static void
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
e1000_led_on(&adapter->hw);
mod_timer(&adapter->blink_timer, jiffies + E1000_ID_INTERVAL);
}
static int
e1000_ethtool_led_blink(struct e1000_adapter *adapter, struct ethtool_value *id)
{
if(!adapter->blink_timer.function) {
init_timer(&adapter->blink_timer);
adapter->blink_timer.function = e1000_led_blink_callback;
adapter->blink_timer.data = (unsigned long) adapter;
}
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);
e1000_cleanup_led(&adapter->hw);
return 0;
}
#endif /* ETHTOOL_PHYS_ID */
int
e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr)
{
......@@ -317,6 +392,22 @@ e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr)
return -EFAULT;
return 0;
}
case ETHTOOL_GREGS: {
struct ethtool_regs regs = {ETHTOOL_GREGS};
uint32_t regs_buff[E1000_REGS_LEN];
if(copy_from_user(&regs, addr, sizeof(regs)))
return -EFAULT;
e1000_ethtool_gregs(adapter, &regs, regs_buff);
if(copy_to_user(addr, &regs, sizeof(regs)))
return -EFAULT;
addr += offsetof(struct ethtool_regs, data);
if(copy_to_user(addr, regs_buff, regs.len))
return -EFAULT;
return 0;
}
case ETHTOOL_NWAY_RST: {
if(!capable(CAP_NET_ADMIN))
return -EPERM;
......@@ -324,6 +415,14 @@ e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr)
e1000_up(adapter);
return 0;
}
#ifdef ETHTOOL_PHYS_ID
case ETHTOOL_PHYS_ID: {
struct ethtool_value id;
if(copy_from_user(&id, addr, sizeof(id)))
return -EFAULT;
return e1000_ethtool_led_blink(adapter, &id);
}
#endif /* ETHTOOL_PHYS_ID */
case ETHTOOL_GLINK: {
struct ethtool_value link = {ETHTOOL_GLINK};
link.data = netif_carrier_ok(netdev);
......
......@@ -93,6 +93,7 @@ static void e1000_shift_out_ee_bits(struct e1000_hw *hw, uint16_t data, uint16_t
static uint16_t e1000_shift_in_ee_bits(struct e1000_hw *hw);
static void e1000_setup_eeprom(struct e1000_hw *hw);
static void e1000_standby_eeprom(struct e1000_hw *hw);
static int32_t e1000_id_led_init(struct e1000_hw * hw);
/******************************************************************************
* Reset the transmit and receive units; mask and clear all interrupts.
......@@ -200,6 +201,13 @@ e1000_init_hw(struct e1000_hw *hw)
DEBUGFUNC("e1000_init_hw");
/* Initialize Identification LED */
ret_val = e1000_id_led_init(hw);
if(ret_val < 0) {
DEBUGOUT("Error Initializing Identification LED\n");
return ret_val;
}
/* Set the Media Type and exit with error if it is not valid. */
if(hw->mac_type != e1000_82543) {
/* tbi_compatibility is only valid on 82543 */
......@@ -541,6 +549,7 @@ e1000_setup_copper_link(struct e1000_hw *hw)
*/
if(hw->mac_type > e1000_82543) {
ctrl |= E1000_CTRL_SLU;
ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
E1000_WRITE_REG(hw, CTRL, ctrl);
} else {
ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU);
......@@ -2087,9 +2096,9 @@ e1000_phy_reset_dsp(struct e1000_hw *hw)
DEBUGFUNC("e1000_phy_reset_dsp");
do {
if(e1000_write_phy_reg(hw, 29, 0x1d) < 0) break;
if(e1000_write_phy_reg(hw, 30, 0xc1) < 0) break;
if(e1000_write_phy_reg(hw, 30, 0x00) < 0) break;
if(e1000_write_phy_reg(hw, 29, 0x001d) < 0) break;
if(e1000_write_phy_reg(hw, 30, 0x00c1) < 0) break;
if(e1000_write_phy_reg(hw, 30, 0x0000) < 0) break;
ret_val = 0;
} while(0);
......@@ -2150,8 +2159,8 @@ e1000_phy_get_info(struct e1000_hw *hw,
M88E1000_PSSR_MDIX_SHIFT;
if(phy_data & M88E1000_PSSR_1000MBS) {
/* Cable Length Estimation and Local/Remote Receiver Informatoion
* are only valid at 1000 Mbps
*/
* are only valid at 1000 Mbps
*/
phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
M88E1000_PSSR_CABLE_LENGTH_SHIFT);
if(e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data) < 0)
......@@ -2785,6 +2794,74 @@ e1000_clear_vfta(struct e1000_hw *hw)
E1000_WRITE_REG_ARRAY(hw, VFTA, offset, 0);
}
static int32_t
e1000_id_led_init(struct e1000_hw * hw)
{
uint32_t ledctl;
const uint32_t ledctl_mask = 0x000000FF;
const uint32_t ledctl_on = E1000_LEDCTL_MODE_LED_ON;
const uint32_t ledctl_off = E1000_LEDCTL_MODE_LED_OFF;
uint16_t eeprom_data, i, temp;
const uint16_t led_mask = 0x0F;
DEBUGFUNC("e1000_id_led_init");
if(hw->mac_type < e1000_82540) {
/* Nothing to do */
return 0;
}
ledctl = E1000_READ_REG(hw, LEDCTL);
hw->ledctl_default = ledctl;
hw->ledctl_mode1 = hw->ledctl_default;
hw->ledctl_mode2 = hw->ledctl_default;
if(e1000_read_eeprom(hw, EEPROM_ID_LED_SETTINGS, &eeprom_data) < 0) {
DEBUGOUT("EEPROM Read Error\n");
return -E1000_ERR_EEPROM;
}
if((eeprom_data== ID_LED_RESERVED_0000) ||
(eeprom_data == ID_LED_RESERVED_FFFF)) eeprom_data = ID_LED_DEFAULT;
for(i = 0; i < 4; i++) {
temp = (eeprom_data >> (i << 2)) & led_mask;
switch(temp) {
case ID_LED_ON1_DEF2:
case ID_LED_ON1_ON2:
case ID_LED_ON1_OFF2:
hw->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
hw->ledctl_mode1 |= ledctl_on << (i << 3);
break;
case ID_LED_OFF1_DEF2:
case ID_LED_OFF1_ON2:
case ID_LED_OFF1_OFF2:
hw->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
hw->ledctl_mode1 |= ledctl_off << (i << 3);
break;
default:
/* Do nothing */
break;
}
switch(temp) {
case ID_LED_DEF1_ON2:
case ID_LED_ON1_ON2:
case ID_LED_OFF1_ON2:
hw->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
hw->ledctl_mode2 |= ledctl_on << (i << 3);
break;
case ID_LED_DEF1_OFF2:
case ID_LED_ON1_OFF2:
case ID_LED_OFF1_OFF2:
hw->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
hw->ledctl_mode2 |= ledctl_off << (i << 3);
break;
default:
/* Do nothing */
break;
}
}
return 0;
}
/******************************************************************************
* Prepares SW controlable LED for use and saves the current state of the LED.
*
......@@ -2809,19 +2886,7 @@ e1000_setup_led(struct e1000_hw *hw)
break;
case E1000_DEV_ID_82540EM:
case E1000_DEV_ID_82540EM_LOM:
ledctl = E1000_READ_REG(hw, LEDCTL);
/* Save current LEDCTL settings */
hw->ledctl = ledctl;
/* Turn off LED2 and LED3 */
ledctl &= ~(E1000_LEDCTL_LED2_IVRT |
E1000_LEDCTL_LED2_BLINK |
E1000_LEDCTL_LED2_MODE_MASK);
ledctl |= (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED2_MODE_SHIFT);
ledctl &= ~(E1000_LEDCTL_LED3_IVRT |
E1000_LEDCTL_LED3_BLINK |
E1000_LEDCTL_LED3_MODE_MASK);
ledctl |= (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED3_MODE_SHIFT);
E1000_WRITE_REG(hw, LEDCTL, ledctl);
E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
break;
default:
DEBUGOUT("Invalid device ID\n");
......@@ -2853,7 +2918,7 @@ e1000_cleanup_led(struct e1000_hw *hw)
case E1000_DEV_ID_82540EM:
case E1000_DEV_ID_82540EM_LOM:
/* Restore LEDCTL settings */
E1000_WRITE_REG(hw, LEDCTL, hw->ledctl);
E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_default);
break;
default:
DEBUGOUT("Invalid device ID\n");
......@@ -2871,7 +2936,6 @@ int32_t
e1000_led_on(struct e1000_hw *hw)
{
uint32_t ctrl;
uint32_t ledctl;
DEBUGFUNC("e1000_led_on");
......@@ -2897,11 +2961,7 @@ e1000_led_on(struct e1000_hw *hw)
break;
case E1000_DEV_ID_82540EM:
case E1000_DEV_ID_82540EM_LOM:
ledctl = E1000_READ_REG(hw, LEDCTL);
/* Set LED 3 mode to on */
ledctl &= ~E1000_LEDCTL_LED3_MODE_MASK;
ledctl |= (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED3_MODE_SHIFT);
E1000_WRITE_REG(hw, LEDCTL, ledctl);
E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode2);
break;
default:
DEBUGOUT("Invalid device ID\n");
......@@ -2919,7 +2979,6 @@ int32_t
e1000_led_off(struct e1000_hw *hw)
{
uint32_t ctrl;
uint32_t ledctl;
DEBUGFUNC("e1000_led_off");
......@@ -2945,11 +3004,7 @@ e1000_led_off(struct e1000_hw *hw)
break;
case E1000_DEV_ID_82540EM:
case E1000_DEV_ID_82540EM_LOM:
ledctl = E1000_READ_REG(hw, LEDCTL);
/* Set LED 3 mode to off */
ledctl &= ~E1000_LEDCTL_LED3_MODE_MASK;
ledctl |= (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED3_MODE_SHIFT);
E1000_WRITE_REG(hw, LEDCTL, ledctl);
E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
break;
default:
DEBUGOUT("Invalid device ID\n");
......
......@@ -882,7 +882,9 @@ struct e1000_hw {
uint32_t num_mc_addrs;
uint32_t collision_delta;
uint32_t tx_packet_delta;
uint32_t ledctl;
uint32_t ledctl_default;
uint32_t ledctl_mode1;
uint32_t ledctl_mode2;
uint16_t autoneg_advertised;
uint16_t pci_cmd_word;
uint16_t fc_high_water;
......@@ -1324,10 +1326,28 @@ struct e1000_hw {
#define EEPROM_EWDS_OPCODE 0x10 /* EERPOM erast/write disable */
/* EEPROM Word Offsets */
#define EEPROM_INIT_CONTROL1_REG 0x000A
#define EEPROM_INIT_CONTROL2_REG 0x000F
#define EEPROM_FLASH_VERSION 0x0032
#define EEPROM_CHECKSUM_REG 0x003F
#define EEPROM_ID_LED_SETTINGS 0x0004
#define EEPROM_INIT_CONTROL1_REG 0x000A
#define EEPROM_INIT_CONTROL2_REG 0x000F
#define EEPROM_FLASH_VERSION 0x0032
#define EEPROM_CHECKSUM_REG 0x003F
/* Word definitions for ID LED Settings */
#define ID_LED_RESERVED_0000 0x0000
#define ID_LED_RESERVED_FFFF 0xFFFF
#define ID_LED_DEFAULT ((ID_LED_OFF1_ON2 << 12) | \
(ID_LED_OFF1_OFF2 << 8) | \
(ID_LED_DEF1_DEF2 << 4) | \
(ID_LED_DEF1_DEF2))
#define ID_LED_DEF1_DEF2 0x1
#define ID_LED_DEF1_ON2 0x2
#define ID_LED_DEF1_OFF2 0x3
#define ID_LED_ON1_DEF2 0x4
#define ID_LED_ON1_ON2 0x5
#define ID_LED_ON1_OFF2 0x6
#define ID_LED_OFF1_DEF2 0x7
#define ID_LED_OFF1_ON2 0x8
#define ID_LED_OFF1_OFF2 0x9
/* Mask bits for fields in Word 0x0a of the EEPROM */
#define EEPROM_WORD0A_ILOS 0x0010
......
......@@ -76,7 +76,7 @@
char e1000_driver_name[] = "e1000";
char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
char e1000_driver_version[] = "4.2.8";
char e1000_driver_version[] = "4.2.9-k1";
char e1000_copyright[] = "Copyright (c) 1999-2002 Intel Corporation.";
/* e1000_pci_tbl - PCI Device ID Table
......@@ -126,7 +126,7 @@ static char *e1000_strings[] = {
"IBM Mobile, Desktop & Server Adapters"
};
/* e1000_main.c Function Prototypes */
/* Local Function Prototypes */
int e1000_up(struct e1000_adapter *adapter);
void e1000_down(struct e1000_adapter *adapter);
......@@ -403,8 +403,10 @@ e1000_probe(struct pci_dev *pdev,
/* make sure the EEPROM is good */
if(e1000_validate_eeprom_checksum(&adapter->hw) < 0)
if(e1000_validate_eeprom_checksum(&adapter->hw) < 0) {
printk(KERN_ERR "The EEPROM Checksum Is Not Valid\n");
goto err_eeprom;
}
/* copy the MAC address out of the EEPROM */
......@@ -437,7 +439,7 @@ e1000_probe(struct pci_dev *pdev,
register_netdev(netdev);
/* we're going to reset, so assume we have no link for now */
netif_carrier_off(netdev);
netif_stop_queue(netdev);
......
......@@ -86,12 +86,14 @@
#include <linux/interrupt.h>
#define usec_delay(x) udelay(x)
#ifndef msec_delay
#define msec_delay(x) do { if(in_interrupt()) { \
mdelay(x); \
} else { \
set_current_state(TASK_UNINTERRUPTIBLE); \
schedule_timeout((x * HZ)/1000); \
} } while(0)
#endif
#define PCI_COMMAND_REGISTER PCI_COMMAND
#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment