Commit 3b9fb4e8 authored by Jeff Garzik's avatar Jeff Garzik

Merge redhat.com:/garz/repo/linus-2.5

into redhat.com:/garz/repo/net-drivers-2.5
parents dc2f9764 26da9f9f
......@@ -671,7 +671,7 @@ static void arcnet_timeout(struct net_device *dev)
* interrupts. Establish which device needs attention, and call the correct
* chipset interrupt handler.
*/
void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
struct arcnet_local *lp;
......@@ -696,7 +696,7 @@ void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
ACOMMAND(CFLAGScmd | RESETclear);
AINTMASK(0);
spin_unlock(&arcnet_lock);
return;
return IRQ_HANDLED;
}
BUGMSG(D_DURING, "in arcnet_inthandler (status=%Xh, intmask=%Xh)\n",
......@@ -864,6 +864,7 @@ void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
AINTMASK(lp->intmask);
spin_unlock(&arcnet_lock);
return IRQ_RETVAL(didsomething);
}
......
......@@ -60,7 +60,14 @@
#include <linux/if_vlan.h>
#include <linux/mii.h>
#define E100_REGS_LEN 1
#define E100_CABLE_UNKNOWN 0
#define E100_CABLE_OK 1
#define E100_CABLE_OPEN_NEAR 2 /* Open Circuit Near End */
#define E100_CABLE_OPEN_FAR 3 /* Open Circuit Far End */
#define E100_CABLE_SHORT_NEAR 4 /* Short Circuit Near End */
#define E100_CABLE_SHORT_FAR 5 /* Short Circuit Far End */
#define E100_REGS_LEN 2
/*
* Configure parameters for buffers per controller.
* If the machine this is being used on is a faster machine (i.e. > 150MHz)
......@@ -105,8 +112,6 @@
#define E100_MAX_CU_IDLE_WAIT 50 /* Max udelays in wait_cus_idle */
/* HWI feature related constant */
#define HWI_MAX_LOOP 100
#define MAX_SAME_RESULTS 3
#define HWI_REGISTER_GRANULARITY 80 /* register granularity = 80 Cm */
#define HWI_NEAR_END_BOUNDARY 1000 /* Near end is defined as < 10 meters */
......@@ -942,7 +947,6 @@ struct e100_private {
#ifdef CONFIG_PM
u32 pci_state[16];
#endif
char ifname[IFNAMSIZ];
#ifdef E100_CU_DEBUG
u8 last_cmd;
u8 last_sub_cmd;
......@@ -956,7 +960,10 @@ struct e100_private {
#define E100_SPEED_100_FULL 4
/********* function prototypes *************/
extern int e100_open(struct net_device *);
extern int e100_close(struct net_device *);
extern void e100_isolate_driver(struct e100_private *bdp);
extern unsigned char e100_hw_init(struct e100_private *);
extern void e100_sw_reset(struct e100_private *bdp, u32 reset_cmd);
extern u8 e100_start_cu(struct e100_private *bdp, tcb_t *tcb);
extern void e100_free_non_tx_cmd(struct e100_private *bdp,
......@@ -981,14 +988,13 @@ extern unsigned char e100_cu_unknown_state(struct e100_private *bdp);
#define TEST_TIMEOUT 0x08
enum test_offsets {
E100_EEPROM_TEST_FAIL = 0,
E100_CHIP_TIMEOUT,
E100_ROM_TEST_FAIL,
E100_REG_TEST_FAIL,
E100_MAC_TEST_FAIL,
E100_LPBK_MAC_FAIL,
E100_LPBK_PHY_FAIL,
E100_MAX_TEST_RES
test_link,
test_eeprom,
test_self_test,
test_loopback_mac,
test_loopback_phy,
cable_diag,
max_test_res, /* must be last */
};
#endif
......@@ -45,6 +45,24 @@
**********************************************************************/
/* Change Log
*
* 2.3.13 05/08/03
* o Feature remove: /proc/net/PRO_LAN_Adapters support gone completely
* o Feature remove: IDIAG support (use ethtool -t instead)
* o Cleanup: fixed spelling mistakes found by community
* o Feature add: ethtool cable diag test
* o Feature add: ethtool parameter support (ring size, xsum, flow ctrl)
* o Cleanup: move e100_asf_enable under CONFIG_PM to avoid warning
* [Stephen Rothwell (sfr@canb.auug.org.au)]
* o Bug fix: don't call any netif_carrier_* until netdev registered.
* [Andrew Morton (akpm@digeo.com)]
* o Cleanup: replace (skb->len - skb->data_len) with skb_headlen(skb)
* [jmorris@intercode.com.au]
* o Bug fix: cleanup of Tx skbs after running ethtool diags
* o Bug fix: incorrect reporting of ethtool diag overall results
* o Bug fix: must hold xmit_lock before stopping queue in ethtool
* operations that require reset h/w and driver structures.
* o Bug fix: statistic command failure would stop statistic collection.
*
* 2.2.21 02/11/03
* o Removed marketing brand strings. Instead, Using generic string
......@@ -61,21 +79,6 @@
* o New feature: added ICH5 support
*
* 2.1.27 11/20/02
* o Bug fix: Device command timeout due to SMBus processing during init
* o Bug fix: Not setting/clearing I (Interrupt) bit in tcb correctly
* o Bug fix: Not using EEPROM WoL setting as default in ethtool
* o Bug fix: Not able to set autoneg on using ethtool when interface down
* o Bug fix: Not able to change speed/duplex using ethtool/mii
* when interface up
* o Bug fix: Ethtool shows autoneg on when forced to 100/Full
* o Bug fix: Compiler error when CONFIG_PROC_FS not defined
* o Bug fix: 2.5.44 e100 doesn't load with preemptive kernel enabled
* (sleep while holding spinlock)
* o Bug fix: 2.1.24-k1 doesn't display complete statistics
* o Bug fix: System panic due to NULL watchdog timer dereference during
* ifconfig down, rmmod and insmod
*
* 2.1.24 10/7/02
*/
#include <linux/config.h>
......@@ -121,14 +124,13 @@ extern void e100_config_wol(struct e100_private *bdp);
extern u32 e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags);
static int e100_ethtool_test(struct net_device *, struct ifreq *);
static int e100_ethtool_gstrings(struct net_device *, struct ifreq *);
static char *test_strings[] = {
"E100_EEPROM_TEST_FAIL",
"E100_CHIP_TIMEOUT",
"E100_ROM_TEST_FAIL",
"E100_REG_TEST_FAIL",
"E100_MAC_TEST_FAIL",
"E100_LPBK_MAC_FAIL",
"E100_LPBK_PHY_FAIL"
static char test_strings[][ETH_GSTRING_LEN] = {
"Link test (on/offline)",
"Eeprom test (on/offline)",
"Self test (offline)",
"Mac loopback (offline)",
"Phy loopback (offline)",
"Cable diagnostic (offline)"
};
static int e100_ethtool_led_blink(struct net_device *, struct ifreq *);
......@@ -139,10 +141,10 @@ static unsigned char e100_delayed_exec_non_cu_cmd(struct e100_private *,
nxmit_cb_entry_t *);
static void e100_free_nontx_list(struct e100_private *);
static void e100_non_tx_background(unsigned long);
static inline void e100_tx_skb_free(struct e100_private *bdp, tcb_t *tcb);
/* Global Data structures and variables */
char e100_copyright[] __devinitdata = "Copyright (c) 2003 Intel Corporation";
char e100_driver_version[]="2.2.21-k1";
char e100_driver_version[]="2.3.13-k1";
const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver";
char e100_short_driver_name[] = "e100";
static int e100nics = 0;
......@@ -155,6 +157,7 @@ static void e100_vlan_rx_kill_vid(struct net_device *netdev, u16 vid);
static int e100_notify_reboot(struct notifier_block *, unsigned long event, void *ptr);
static int e100_suspend(struct pci_dev *pcid, u32 state);
static int e100_resume(struct pci_dev *pcid);
static unsigned char e100_asf_enabled(struct e100_private *bdp);
struct notifier_block e100_notifier_reboot = {
.notifier_call = e100_notify_reboot,
.next = NULL,
......@@ -182,8 +185,6 @@ struct notifier_block e100_notifier_reboot = {
static u8 e100_D101M_checksum(struct e100_private *, struct sk_buff *);
static u8 e100_D102_check_checksum(rfd_t *);
static int e100_ioctl(struct net_device *, struct ifreq *, int);
static int e100_open(struct net_device *);
static int e100_close(struct net_device *);
static int e100_change_mtu(struct net_device *, int);
static int e100_xmit_frame(struct sk_buff *, struct net_device *);
static unsigned char e100_init(struct e100_private *);
......@@ -193,7 +194,6 @@ struct net_device_stats *e100_get_stats(struct net_device *);
static irqreturn_t e100intr(int, void *, struct pt_regs *);
static void e100_print_brd_conf(struct e100_private *);
static void e100_set_multi(struct net_device *);
void e100_set_speed_duplex(struct e100_private *);
static u8 e100_pci_setup(struct pci_dev *, struct e100_private *);
static u8 e100_sw_init(struct e100_private *);
......@@ -215,7 +215,6 @@ u16 e100_eeprom_calculate_chksum(struct e100_private *adapter);
static unsigned char e100_clr_cntrs(struct e100_private *);
static unsigned char e100_load_microcode(struct e100_private *);
static unsigned char e100_hw_init(struct e100_private *);
static unsigned char e100_setup_iaaddr(struct e100_private *, u8 *);
static unsigned char e100_update_stats(struct e100_private *bdp);
......@@ -228,7 +227,6 @@ static void e100_set_bool_option(struct e100_private *bdp, int, u32, int,
char *);
unsigned char e100_wait_exec_cmplx(struct e100_private *, u32, u8, u8);
void e100_exec_cmplx(struct e100_private *, u32, u8);
static unsigned char e100_asf_enabled(struct e100_private *bdp);
/**
* e100_get_rx_struct - retrieve cell to hold skb buff from the pool
......@@ -616,6 +614,10 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
goto err_dealloc;
}
if ((rc = register_netdev(dev)) != 0) {
goto err_pci;
}
if (((bdp->pdev->device > 0x1030)
&& (bdp->pdev->device < 0x103F))
|| ((bdp->pdev->device >= 0x1050)
......@@ -645,7 +647,7 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
printk(KERN_ERR "e100: Failed to initialize, instance #%d\n",
e100nics);
rc = -ENODEV;
goto err_pci;
goto err_unregister_netdev;
}
/* Check if checksum is valid */
......@@ -655,7 +657,7 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
printk(KERN_ERR "e100: Corrupted EEPROM on instance #%d\n",
e100nics);
rc = -ENODEV;
goto err_pci;
goto err_unregister_netdev;
}
dev->vlan_rx_register = e100_vlan_rx_register;
......@@ -679,12 +681,6 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
e100_get_speed_duplex_caps(bdp);
if ((rc = register_netdev(dev)) != 0) {
goto err_pci;
}
memcpy(bdp->ifname, dev->name, IFNAMSIZ);
bdp->ifname[IFNAMSIZ-1] = 0;
printk(KERN_NOTICE
"e100: %s: %s\n",
bdp->device->name, "Intel(R) PRO/100 Network Connection");
......@@ -709,6 +705,8 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
goto out;
err_unregister_netdev:
unregister_netdev(dev);
err_pci:
iounmap(bdp->scb);
pci_release_regions(pcid);
......@@ -974,7 +972,7 @@ e100_set_bool_option(struct e100_private *bdp, int val, u32 mask,
}
}
static int
int
e100_open(struct net_device *dev)
{
struct e100_private *bdp;
......@@ -1033,7 +1031,7 @@ e100_open(struct net_device *dev)
return rc;
}
static int
int
e100_close(struct net_device *dev)
{
struct e100_private *bdp = dev->priv;
......@@ -1285,10 +1283,8 @@ e100_init(struct e100_private *bdp)
/* read NIC's part number */
e100_rd_pwa_no(bdp);
if (!e100_hw_init(bdp)) {
printk(KERN_ERR "e100: hw init failed\n");
if (!e100_hw_init(bdp))
return false;
}
/* Interrupts are enabled after device reset */
e100_disable_clear_intr(bdp);
......@@ -1330,6 +1326,8 @@ e100_sw_init(struct e100_private *bdp)
spin_lock_init(&(bdp->bd_non_tx_lock));
spin_lock_init(&(bdp->config_lock));
spin_lock_init(&(bdp->mdi_access_lock));
/* Initialize configuration data */
e100_config_init(bdp);
return 1;
}
......@@ -1384,11 +1382,11 @@ e100_tco_workaround(struct e100_private *bdp)
* true - If the adapter was initialized
* false - If the adapter failed initialization
*/
unsigned char __devinit
unsigned char
e100_hw_init(struct e100_private *bdp)
{
if (!e100_phy_init(bdp))
return false;
goto err;
e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
......@@ -1398,27 +1396,25 @@ e100_hw_init(struct e100_private *bdp)
/* Load the CU BASE (set to 0, because we use linear mode) */
if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0))
return false;
goto err;
if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0))
return false;
goto err;
/* Load interrupt microcode */
if (e100_load_microcode(bdp)) {
bdp->flags |= DF_UCODE_LOADED;
}
e100_config_init(bdp);
if (!e100_config(bdp)) {
return false;
}
if (!e100_config(bdp))
goto err;
if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr))
return false;
goto err;
/* Clear the internal counters */
if (!e100_clr_cntrs(bdp))
return false;
goto err;
/* Change for 82558 enhancement */
/* If 82558/9 and if the user has enabled flow control, set up the
......@@ -1431,6 +1427,9 @@ e100_hw_init(struct e100_private *bdp)
}
return true;
err:
printk(KERN_ERR "e100: hw init failed\n");
return false;
}
/**
......@@ -1591,9 +1590,22 @@ e100_alloc_tcb_pool(struct e100_private *bdp)
void
e100_free_tcb_pool(struct e100_private *bdp)
{
tcb_t *tcb;
int i;
/* Return tx skbs */
for (i = 0; i < bdp->params.TxDescriptors; i++) {
tcb = bdp->tcb_pool.data;
tcb += bdp->tcb_pool.head;
e100_tx_skb_free(bdp, tcb);
if (NEXT_TCB_TOUSE(bdp->tcb_pool.head) == bdp->tcb_pool.tail)
break;
bdp->tcb_pool.head = NEXT_TCB_TOUSE(bdp->tcb_pool.head);
}
pci_free_consistent(bdp->pdev,
sizeof (tcb_t) * bdp->params.TxDescriptors,
bdp->tcb_pool.data, bdp->tcb_phys);
bdp->tcb_pool.head = 0;
bdp->tcb_pool.tail = 1;
bdp->tcb_phys = 0;
}
......@@ -1747,12 +1759,10 @@ e100_watchdog(struct net_device *dev)
e100_set_multi(dev);
}
}
/* Update the statistics needed by the upper interface */
/* This should be the last statistic related command
* as it's async. now */
e100_dump_stats_cntrs(bdp);
}
/* Issue command to dump statistics from device. */
/* Check for command completion on next watchdog timer. */
e100_dump_stats_cntrs(bdp);
wmb();
......@@ -2544,6 +2554,7 @@ e100_update_stats(struct e100_private *bdp)
pcmd_complete = e100_cmd_complete_location(bdp);
if (*pcmd_complete != le32_to_cpu(DUMP_RST_STAT_COMPLETED) &&
*pcmd_complete != le32_to_cpu(DUMP_STAT_COMPLETED)) {
*pcmd_complete = 0;
return false;
}
......@@ -3041,23 +3052,6 @@ e100_isolate_driver(struct e100_private *bdp)
e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
}
void
e100_set_speed_duplex(struct e100_private *bdp)
{
int carrier_ok;
/* Device may lose link with some siwtches when */
/* changing speed/duplex to non-autoneg. e100 */
/* needs to remember carrier state in order to */
/* start watchdog timer for recovering link */
if ((carrier_ok = netif_carrier_ok(bdp->device)))
e100_isolate_driver(bdp);
e100_phy_set_speed_duplex(bdp, true);
e100_config_fc(bdp); /* re-config flow-control if necessary */
e100_config(bdp);
if (carrier_ok)
e100_deisolate_driver(bdp, false);
}
static void
e100_tcb_add_C_bit(struct e100_private *bdp)
{
......@@ -3213,6 +3207,144 @@ e100_do_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
case ETHTOOL_PHYS_ID:
rc = e100_ethtool_led_blink(dev,ifr);
break;
#ifdef ETHTOOL_GRINGPARAM
case ETHTOOL_GRINGPARAM: {
struct ethtool_ringparam ering;
struct e100_private *bdp = dev->priv;
memset((void *) &ering, 0, sizeof(ering));
ering.rx_max_pending = E100_MAX_RFD;
ering.tx_max_pending = E100_MAX_TCB;
ering.rx_pending = bdp->params.RxDescriptors;
ering.tx_pending = bdp->params.TxDescriptors;
rc = copy_to_user(ifr->ifr_data, &ering, sizeof(ering))
? -EFAULT : 0;
return rc;
}
#endif
#ifdef ETHTOOL_SRINGPARAM
case ETHTOOL_SRINGPARAM: {
struct ethtool_ringparam ering;
struct e100_private *bdp = dev->priv;
if (copy_from_user(&ering, ifr->ifr_data, sizeof(ering)))
return -EFAULT;
if (ering.rx_pending > E100_MAX_RFD
|| ering.rx_pending < E100_MIN_RFD)
return -EINVAL;
if (ering.tx_pending > E100_MAX_TCB
|| ering.tx_pending < E100_MIN_TCB)
return -EINVAL;
if (netif_running(dev)) {
spin_lock_bh(&dev->xmit_lock);
e100_close(dev);
spin_unlock_bh(&dev->xmit_lock);
/* Use new values to open interface */
bdp->params.RxDescriptors = ering.rx_pending;
bdp->params.TxDescriptors = ering.tx_pending;
e100_hw_init(bdp);
e100_open(dev);
}
else {
bdp->params.RxDescriptors = ering.rx_pending;
bdp->params.TxDescriptors = ering.tx_pending;
}
return 0;
}
#endif
#ifdef ETHTOOL_GPAUSEPARAM
case ETHTOOL_GPAUSEPARAM: {
struct ethtool_pauseparam epause;
struct e100_private *bdp = dev->priv;
memset((void *) &epause, 0, sizeof(epause));
if ((bdp->flags & IS_BACHELOR)
&& (bdp->params.b_params & PRM_FC)) {
epause.autoneg = 1;
if (bdp->flags && DF_LINK_FC_CAP) {
epause.rx_pause = 1;
epause.tx_pause = 1;
}
if (bdp->flags && DF_LINK_FC_TX_ONLY)
epause.tx_pause = 1;
}
rc = copy_to_user(ifr->ifr_data, &epause, sizeof(epause))
? -EFAULT : 0;
return rc;
}
#endif
#ifdef ETHTOOL_SPAUSEPARAM
case ETHTOOL_SPAUSEPARAM: {
struct ethtool_pauseparam epause;
struct e100_private *bdp = dev->priv;
if (!(bdp->flags & IS_BACHELOR))
return -EINVAL;
if (copy_from_user(&epause, ifr->ifr_data, sizeof(epause)))
return -EFAULT;
if (epause.autoneg == 1)
bdp->params.b_params |= PRM_FC;
else
bdp->params.b_params &= ~PRM_FC;
if (netif_running(dev)) {
spin_lock_bh(&dev->xmit_lock);
e100_close(dev);
spin_unlock_bh(&dev->xmit_lock);
e100_hw_init(bdp);
e100_open(dev);
}
return 0;
}
#endif
#ifdef ETHTOOL_GRXCSUM
case ETHTOOL_GRXCSUM:
case ETHTOOL_GTXCSUM:
case ETHTOOL_GSG:
{ struct ethtool_value eval;
struct e100_private *bdp = dev->priv;
memset((void *) &eval, 0, sizeof(eval));
if ((ecmd.cmd == ETHTOOL_GRXCSUM)
&& (bdp->params.b_params & PRM_XSUMRX))
eval.data = 1;
else
eval.data = 0;
rc = copy_to_user(ifr->ifr_data, &eval, sizeof(eval))
? -EFAULT : 0;
return rc;
}
#endif
#ifdef ETHTOOL_SRXCSUM
case ETHTOOL_SRXCSUM:
case ETHTOOL_STXCSUM:
case ETHTOOL_SSG:
{ struct ethtool_value eval;
struct e100_private *bdp = dev->priv;
if (copy_from_user(&eval, ifr->ifr_data, sizeof(eval)))
return -EFAULT;
if (ecmd.cmd == ETHTOOL_SRXCSUM) {
if (eval.data == 1) {
if (bdp->rev_id >= D101MA_REV_ID)
bdp->params.b_params |= PRM_XSUMRX;
else
return -EINVAL;
} else {
if (bdp->rev_id >= D101MA_REV_ID)
bdp->params.b_params &= ~PRM_XSUMRX;
else
return 0;
}
} else {
if (eval.data == 1)
return -EINVAL;
else
return 0;
}
if (netif_running(dev)) {
spin_lock_bh(&dev->xmit_lock);
e100_close(dev);
spin_unlock_bh(&dev->xmit_lock);
e100_hw_init(bdp);
e100_open(dev);
}
return 0;
}
#endif
default:
break;
} //switch
......@@ -3364,14 +3496,14 @@ e100_ethtool_test(struct net_device *dev, struct ifreq *ifr)
struct ethtool_test *info;
int rc = -EFAULT;
info = kmalloc(sizeof(*info) + E100_MAX_TEST_RES * sizeof(u64),
info = kmalloc(sizeof(*info) + max_test_res * sizeof(u64),
GFP_ATOMIC);
if (!info)
return -ENOMEM;
memset((void *) info, 0, sizeof(*info) +
E100_MAX_TEST_RES * sizeof(u64));
max_test_res * sizeof(u64));
if (copy_from_user(info, ifr->ifr_data, sizeof(*info)))
goto exit;
......@@ -3379,7 +3511,7 @@ e100_ethtool_test(struct net_device *dev, struct ifreq *ifr)
info->flags = e100_run_diag(dev, info->data, info->flags);
if (!copy_to_user(ifr->ifr_data, info,
sizeof(*info) + E100_MAX_TEST_RES * sizeof(u64)))
sizeof(*info) + max_test_res * sizeof(u64)))
rc = 0;
exit:
kfree(info);
......@@ -3393,6 +3525,7 @@ e100_ethtool_gregs(struct net_device *dev, struct ifreq *ifr)
u32 regs_buff[E100_REGS_LEN];
struct ethtool_regs regs = {ETHTOOL_GREGS};
void *addr = ifr->ifr_data;
u16 mdi_reg;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
......@@ -3405,6 +3538,8 @@ e100_ethtool_gregs(struct net_device *dev, struct ifreq *ifr)
regs_buff[0] = readb(&(bdp->scb->scb_cmd_hi)) << 24 |
readb(&(bdp->scb->scb_cmd_low)) << 16 |
readw(&(bdp->scb->scb_status));
e100_mdi_read(bdp, MII_NCONFIG, bdp->phy_addr, &mdi_reg);
regs_buff[1] = mdi_reg;
if(copy_to_user(addr, &regs, sizeof(regs)))
return -EFAULT;
......@@ -3454,7 +3589,7 @@ e100_ethtool_get_drvinfo(struct net_device *dev, struct ifreq *ifr)
info.n_stats = E100_STATS_LEN;
info.regdump_len = E100_REGS_LEN * sizeof(u32);
info.eedump_len = (bdp->eeprom_size << 1);
info.testinfo_len = E100_MAX_TEST_RES;
info.testinfo_len = max_test_res;
if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
return -EFAULT;
......@@ -3804,15 +3939,15 @@ static int e100_ethtool_gstrings(struct net_device *dev, struct ifreq *ifr)
switch (info.string_set) {
case ETH_SS_TEST: {
int ret = 0;
if (info.len > E100_MAX_TEST_RES)
info.len = E100_MAX_TEST_RES;
if (info.len > max_test_res)
info.len = max_test_res;
strings = kmalloc(info.len * ETH_GSTRING_LEN, GFP_ATOMIC);
if (!strings)
return -ENOMEM;
memset(strings, 0, info.len * ETH_GSTRING_LEN);
for (i = 0; i < info.len; i++) {
sprintf(strings + i * ETH_GSTRING_LEN, "%-31s",
sprintf(strings + i * ETH_GSTRING_LEN, "%s",
test_strings[i]);
}
if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
......@@ -4164,7 +4299,6 @@ e100_resume(struct pci_dev *pcid)
return 0;
}
#endif /* CONFIG_PM */
/**
* e100_asf_enabled - checks if ASF is configured on the current adaper
......@@ -4190,6 +4324,7 @@ e100_asf_enabled(struct e100_private *bdp)
}
return false;
}
#endif /* CONFIG_PM */
#ifdef E100_CU_DEBUG
unsigned char
......
......@@ -628,8 +628,6 @@ e100_force_speed_duplex(struct e100_private *bdp)
u16 control;
unsigned long expires;
e100_phy_reset(bdp);
bdp->flags |= DF_SPEED_FORCED;
e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control);
......@@ -912,6 +910,10 @@ e100_phy_reset(struct e100_private *bdp)
u16 ctrl_reg;
ctrl_reg = BMCR_RESET;
e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg);
/* ieee 802.3 : The reset process shall be completed */
/* within 0.5 seconds from the settting of PHY reset bit. */
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ / 2);
}
unsigned char __devinit
......@@ -928,6 +930,7 @@ e100_phy_init(struct e100_private *bdp)
bdp->PhyDelay = 0;
bdp->zlock_state = ZLOCK_INITIAL;
e100_phy_reset(bdp);
e100_phy_set_speed_duplex(bdp, false);
e100_fix_polarity(bdp);
......
......@@ -25,7 +25,7 @@
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
#include "e100.h"
#include "e100_phy.h"
#include "e100_config.h"
extern u16 e100_eeprom_read(struct e100_private *, u16);
......@@ -46,6 +46,7 @@ static u8 e100_diag_loopback_alloc(struct e100_private *);
static void e100_diag_loopback_cu_ru_exec(struct e100_private *);
static u8 e100_diag_check_pkt(u8 *);
static void e100_diag_loopback_free(struct e100_private *);
static int e100_cable_diag(struct e100_private *bdp);
#define LB_PACKET_SIZE 1500
......@@ -60,46 +61,52 @@ u32
e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags)
{
struct e100_private* bdp = dev->priv;
u8 test_result = true;
e100_isolate_driver(bdp);
u8 test_result = 0;
if (!e100_get_link_state(bdp)) {
test_result = ETH_TEST_FL_FAILED;
test_info[test_link] = true;
}
if (!e100_diag_eeprom(dev)) {
test_result = ETH_TEST_FL_FAILED;
test_info[test_eeprom] = true;
}
if (flags & ETH_TEST_FL_OFFLINE) {
u8 fail_mask;
fail_mask = e100_diag_selftest(dev);
if (fail_mask) {
test_result = false;
if (fail_mask & REGISTER_TEST_FAIL)
test_info [E100_REG_TEST_FAIL] = true;
if (fail_mask & ROM_TEST_FAIL)
test_info [E100_ROM_TEST_FAIL] = true;
if (fail_mask & SELF_TEST_FAIL)
test_info [E100_MAC_TEST_FAIL] = true;
if (fail_mask & TEST_TIMEOUT)
test_info [E100_CHIP_TIMEOUT] = true;
if (netif_running(dev)) {
spin_lock_bh(&dev->xmit_lock);
e100_close(dev);
spin_unlock_bh(&dev->xmit_lock);
}
if (e100_diag_selftest(dev)) {
test_result = ETH_TEST_FL_FAILED;
test_info[test_self_test] = true;
}
fail_mask = e100_diag_loopback(dev);
if (fail_mask) {
test_result = false;
test_result = ETH_TEST_FL_FAILED;
if (fail_mask & PHY_LOOPBACK)
test_info [E100_LPBK_PHY_FAIL] = true;
test_info[test_loopback_phy] = true;
if (fail_mask & MAC_LOOPBACK)
test_info [E100_LPBK_MAC_FAIL] = true;
}
test_info[test_loopback_mac] = true;
}
if (!e100_diag_eeprom(dev)) {
test_result = false;
test_info [E100_EEPROM_TEST_FAIL] = true;
test_info[cable_diag] = e100_cable_diag(bdp);
/* Need hw init regardless of netif_running */
e100_hw_init(bdp);
if (netif_running(dev)) {
e100_open(dev);
}
}
else {
test_info[test_self_test] = false;
test_info[test_loopback_phy] = false;
test_info[test_loopback_mac] = false;
test_info[cable_diag] = false;
}
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ * 2);
e100_deisolate_driver(bdp, false);
return flags | (test_result ? 0 : ETH_TEST_FL_FAILED);
return flags | test_result;
}
/**
......@@ -126,8 +133,6 @@ e100_diag_selftest(struct net_device *dev)
}
}
e100_configure_device(bdp);
return retval;
}
......@@ -165,14 +170,14 @@ e100_diag_loopback (struct net_device *dev)
u8 rc = 0;
printk(KERN_DEBUG "%s: PHY loopback test starts\n", dev->name);
e100_sw_reset(dev->priv, PORT_SELECTIVE_RESET);
e100_hw_init(dev->priv);
if (!e100_diag_one_loopback(dev, PHY_LOOPBACK)) {
rc |= PHY_LOOPBACK;
}
printk(KERN_DEBUG "%s: PHY loopback test ends\n", dev->name);
printk(KERN_DEBUG "%s: MAC loopback test starts\n", dev->name);
e100_sw_reset(dev->priv, PORT_SELECTIVE_RESET);
e100_hw_init(dev->priv);
if (!e100_diag_one_loopback(dev, MAC_LOOPBACK)) {
rc |= MAC_LOOPBACK;
}
......@@ -257,14 +262,9 @@ e100_diag_config_loopback(struct e100_private* bdp,
if (set_loopback)
/* Set PHY loopback mode */
e100_phy_set_loopback(bdp);
else { /* Back to normal speed and duplex */
if (bdp->params.e100_speed_duplex == E100_AUTONEG)
/* Reset PHY and do autoneg */
e100_phy_autoneg(bdp);
else
/* Reset PHY and force speed and duplex */
e100_force_speed_duplex(bdp);
}
/* Reset PHY loopback mode */
e100_phy_reset(bdp);
/* Wait for PHY state change */
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ);
......@@ -348,10 +348,6 @@ static void
e100_diag_loopback_cu_ru_exec(struct e100_private *bdp)
{
/*load CU & RU base */
if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0))
printk(KERN_ERR "e100: SCB_CUC_LOAD_BASE failed\n");
if(!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0))
printk(KERN_ERR "e100: SCB_RUC_LOAD_BASE failed!\n");
if(!e100_wait_exec_cmplx(bdp, bdp->loopback.dma_handle, SCB_RUC_START, 0))
printk(KERN_ERR "e100: SCB_RUC_START failed!\n");
......@@ -433,3 +429,72 @@ e100_diag_loopback_free (struct e100_private *bdp)
bdp->loopback.dma_handle);
}
static int
e100_cable_diag(struct e100_private *bdp)
{
int saved_open_circut = 0xffff;
int saved_short_circut = 0xffff;
int saved_distance = 0xffff;
int saved_same = 0;
int cable_status = E100_CABLE_UNKNOWN;
int i;
/* If we have link, */
if (e100_get_link_state(bdp))
return E100_CABLE_OK;
if (bdp->rev_id < D102_REV_ID)
return E100_CABLE_UNKNOWN;
/* Disable MDI/MDI-X auto switching */
e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr,
MDI_MDIX_RESET_ALL_MASK);
/* Set to 100 Full as required by cable test */
e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr,
BMCR_SPEED100 | BMCR_FULLDPLX);
/* Test up to 100 times */
for (i = 0; i < 100; i++) {
u16 ctrl_reg;
int distance, open_circut, short_circut, near_end;
/* Enable and execute cable test */
e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr,
(HWI_TEST_ENABLE | HWI_TEST_EXECUTE));
/* Wait for cable test finished */
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ/100 + 1);
/* Read results */
e100_mdi_read(bdp, HWI_CONTROL_REG, bdp->phy_addr, &ctrl_reg);
distance = ctrl_reg & HWI_TEST_DISTANCE;
open_circut = ctrl_reg & HWI_TEST_HIGHZ_PROBLEM;
short_circut = ctrl_reg & HWI_TEST_LOWZ_PROBLEM;
if ((distance == saved_distance) &&
(open_circut == saved_open_circut) &&
(short_circut == saved_short_circut))
saved_same++;
else {
saved_same = 0;
saved_distance = distance;
saved_open_circut = open_circut;
saved_short_circut = short_circut;
}
/* If results are the same 3 times */
if (saved_same == 3) {
near_end = ((distance * HWI_REGISTER_GRANULARITY) <
HWI_NEAR_END_BOUNDARY);
if (open_circut)
cable_status = (near_end) ?
E100_CABLE_OPEN_NEAR : E100_CABLE_OPEN_FAR;
if (short_circut)
cable_status = (near_end) ?
E100_CABLE_SHORT_NEAR : E100_CABLE_SHORT_FAR;
break;
}
}
/* Reset cable test */
e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr, HWI_RESET_ALL_MASK);
return cable_status;
}
################################################################################
#
#
# 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
......
......@@ -134,6 +134,7 @@ struct e1000_buffer {
uint64_t dma;
unsigned long length;
unsigned long time_stamp;
unsigned int next_to_watch;
};
struct e1000_desc_ring {
......@@ -169,7 +170,6 @@ struct e1000_adapter {
struct timer_list watchdog_timer;
struct timer_list phy_info_timer;
struct vlan_group *vlgrp;
char *id_string;
uint32_t bd_number;
uint32_t rx_buffer_len;
uint32_t part_num;
......@@ -218,6 +218,9 @@ struct e1000_adapter {
struct e1000_phy_info phy_info;
struct e1000_phy_stats phy_stats;
uint32_t test_icr;
struct e1000_desc_ring test_tx_ring;
struct e1000_desc_ring test_rx_ring;
uint32_t pci_state[16];
......
......@@ -40,15 +40,60 @@ 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",
struct e1000_stats {
char stat_string[ETH_GSTRING_LEN];
int sizeof_stat;
int stat_offset;
};
#define E1000_STATS_LEN sizeof(e1000_gstrings_stats) / ETH_GSTRING_LEN
#define E1000_STAT(m) sizeof(((struct e1000_adapter *)0)->m), \
offsetof(struct e1000_adapter, m)
static struct e1000_stats e1000_gstrings_stats[] = {
{ "rx_packets", E1000_STAT(net_stats.rx_packets) },
{ "tx_packets", E1000_STAT(net_stats.tx_packets) },
{ "rx_bytes", E1000_STAT(net_stats.rx_bytes) },
{ "tx_bytes", E1000_STAT(net_stats.tx_bytes) },
{ "rx_errors", E1000_STAT(net_stats.rx_errors) },
{ "tx_errors", E1000_STAT(net_stats.tx_errors) },
{ "rx_dropped", E1000_STAT(net_stats.rx_dropped) },
{ "tx_dropped", E1000_STAT(net_stats.tx_dropped) },
{ "multicast", E1000_STAT(net_stats.multicast) },
{ "collisions", E1000_STAT(net_stats.collisions) },
{ "rx_length_errors", E1000_STAT(net_stats.rx_length_errors) },
{ "rx_over_errors", E1000_STAT(net_stats.rx_over_errors) },
{ "rx_crc_errors", E1000_STAT(net_stats.rx_crc_errors) },
{ "rx_frame_errors", E1000_STAT(net_stats.rx_frame_errors) },
{ "rx_fifo_errors", E1000_STAT(net_stats.rx_fifo_errors) },
{ "rx_missed_errors", E1000_STAT(net_stats.rx_missed_errors) },
{ "tx_aborted_errors", E1000_STAT(net_stats.tx_aborted_errors) },
{ "tx_carrier_errors", E1000_STAT(net_stats.tx_carrier_errors) },
{ "tx_fifo_errors", E1000_STAT(net_stats.tx_fifo_errors) },
{ "tx_heartbeat_errors", E1000_STAT(net_stats.tx_heartbeat_errors) },
{ "tx_window_errors", E1000_STAT(net_stats.tx_window_errors) },
{ "tx_abort_late_coll", E1000_STAT(stats.latecol) },
{ "tx_deferred_ok", E1000_STAT(stats.dc) },
{ "tx_single_coll_ok", E1000_STAT(stats.scc) },
{ "tx_multi_coll_ok", E1000_STAT(stats.mcc) },
{ "rx_long_length_errors", E1000_STAT(stats.roc) },
{ "rx_short_length_errors", E1000_STAT(stats.ruc) },
{ "rx_align_errors", E1000_STAT(stats.algnerrc) },
{ "tx_tcp_seg_good", E1000_STAT(stats.tsctc) },
{ "tx_tcp_seg_failed", E1000_STAT(stats.tsctfc) },
{ "rx_flow_control_xon", E1000_STAT(stats.xonrxc) },
{ "rx_flow_control_xoff", E1000_STAT(stats.xoffrxc) },
{ "tx_flow_control_xon", E1000_STAT(stats.xontxc) },
{ "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) },
{ "rx_csum_offload_good", E1000_STAT(hw_csum_good) },
{ "rx_csum_offload_errors", E1000_STAT(hw_csum_err) }
};
#define E1000_STATS_LEN \
sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats)
static char e1000_gstrings_test[][ETH_GSTRING_LEN] = {
"Register test (offline)", "Eeprom test (offline)",
"Interrupt test (offline)", "Loopback test (offline)",
"Link test (on/offline)"
};
#define E1000_TEST_LEN sizeof(e1000_gstrings_test) / ETH_GSTRING_LEN
static void
e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
......@@ -154,6 +199,7 @@ e1000_ethtool_gdrvinfo(struct e1000_adapter *adapter,
strncpy(drvinfo->fw_version, "N/A", 32);
strncpy(drvinfo->bus_info, adapter->pdev->slot_name, 32);
drvinfo->n_stats = E1000_STATS_LEN;
drvinfo->testinfo_len = E1000_TEST_LEN;
#define E1000_REGS_LEN 32
drvinfo->regdump_len = E1000_REGS_LEN * sizeof(uint32_t);
drvinfo->eedump_len = adapter->hw.eeprom.word_size * 2;
......@@ -164,6 +210,7 @@ e1000_ethtool_gregs(struct e1000_adapter *adapter,
struct ethtool_regs *regs, uint32_t *regs_buff)
{
struct e1000_hw *hw = &adapter->hw;
uint16_t phy_data;
regs->version = (1 << 24) | (hw->revision_id << 16) | hw->device_id;
......@@ -182,6 +229,62 @@ e1000_ethtool_gregs(struct e1000_adapter *adapter,
regs_buff[10] = E1000_READ_REG(hw, TDT);
regs_buff[11] = E1000_READ_REG(hw, TIDV);
regs_buff[12] = adapter->hw.phy_type; /* PHY type (IGP=1, M88=0) */
if(hw->phy_type == e1000_phy_igp) {
e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,
IGP01E1000_PHY_AGC_A);
e1000_read_phy_reg(hw, IGP01E1000_PHY_AGC_A &
IGP01E1000_PHY_PAGE_SELECT, &phy_data);
regs_buff[13] = (uint32_t)phy_data; /* cable length */
e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,
IGP01E1000_PHY_AGC_B);
e1000_read_phy_reg(hw, IGP01E1000_PHY_AGC_B &
IGP01E1000_PHY_PAGE_SELECT, &phy_data);
regs_buff[14] = (uint32_t)phy_data; /* cable length */
e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,
IGP01E1000_PHY_AGC_C);
e1000_read_phy_reg(hw, IGP01E1000_PHY_AGC_C &
IGP01E1000_PHY_PAGE_SELECT, &phy_data);
regs_buff[15] = (uint32_t)phy_data; /* cable length */
e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,
IGP01E1000_PHY_AGC_D);
e1000_read_phy_reg(hw, IGP01E1000_PHY_AGC_D &
IGP01E1000_PHY_PAGE_SELECT, &phy_data);
regs_buff[16] = (uint32_t)phy_data; /* cable length */
regs_buff[17] = 0; /* extended 10bt distance (not needed) */
e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0);
e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS &
IGP01E1000_PHY_PAGE_SELECT, &phy_data);
regs_buff[18] = (uint32_t)phy_data; /* cable polarity */
e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,
IGP01E1000_PHY_PCS_INIT_REG);
e1000_read_phy_reg(hw, IGP01E1000_PHY_PCS_INIT_REG &
IGP01E1000_PHY_PAGE_SELECT, &phy_data);
regs_buff[19] = (uint32_t)phy_data; /* cable polarity */
regs_buff[20] = 0; /* polarity correction enabled (always) */
regs_buff[22] = 0; /* phy receive errors (unavailable) */
regs_buff[23] = regs_buff[18]; /* mdix mode */
e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0);
} else {
e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
regs_buff[13] = (uint32_t)phy_data; /* cable length */
regs_buff[14] = 0; /* Dummy (to align w/ IGP phy reg dump) */
regs_buff[15] = 0; /* Dummy (to align w/ IGP phy reg dump) */
regs_buff[16] = 0; /* Dummy (to align w/ IGP phy reg dump) */
e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
regs_buff[17] = (uint32_t)phy_data; /* extended 10bt distance */
regs_buff[18] = regs_buff[13]; /* cable polarity */
regs_buff[19] = 0; /* Dummy (to align w/ IGP phy reg dump) */
regs_buff[20] = regs_buff[17]; /* polarity correction */
/* phy receive errors */
regs_buff[22] = adapter->phy_stats.receive_errors;
regs_buff[23] = regs_buff[13]; /* mdix mode */
}
regs_buff[21] = adapter->phy_stats.idle_errors; /* phy idle errors */
e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data);
regs_buff[24] = (uint32_t)phy_data; /* phy local receiver status */
regs_buff[25] = regs_buff[24]; /* phy remote receiver status */
return;
}
......@@ -249,7 +352,7 @@ e1000_ethtool_seeprom(struct e1000_adapter *adapter,
first_word = eeprom->offset >> 1;
last_word = (eeprom->offset + eeprom->len - 1) >> 1;
eeprom_buff = kmalloc(max_len, GFP_KERNEL);
if(eeprom_buff == NULL)
if(!eeprom_buff)
return -ENOMEM;
ptr = (void *)eeprom_buff;
......@@ -284,6 +387,765 @@ e1000_ethtool_seeprom(struct e1000_adapter *adapter,
return ret_val;
}
#define REG_PATTERN_TEST(R, M, W) \
{ \
uint32_t pat, value; \
uint32_t test[] = \
{0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \
for(pat = 0; pat < sizeof(test)/sizeof(test[0]); pat++) { \
E1000_WRITE_REG(&adapter->hw, R, (test[pat] & W)); \
value = E1000_READ_REG(&adapter->hw, R); \
if(value != (test[pat] & W & M)) { \
*data = (adapter->hw.mac_type < e1000_82543) ? \
E1000_82542_##R : E1000_##R; \
return 1; \
} \
} \
}
#define REG_SET_AND_CHECK(R, M, W) \
{ \
uint32_t value; \
E1000_WRITE_REG(&adapter->hw, R, W & M); \
value = E1000_READ_REG(&adapter->hw, R); \
if ((W & M) != (value & M)) { \
*data = (adapter->hw.mac_type < e1000_82543) ? \
E1000_82542_##R : E1000_##R; \
return 1; \
} \
}
static int
e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data)
{
uint32_t value;
uint32_t i;
/* The status register is Read Only, so a write should fail.
* Some bits that get toggled are ignored.
*/
value = (E1000_READ_REG(&adapter->hw, STATUS) & (0xFFFFF833));
E1000_WRITE_REG(&adapter->hw, STATUS, (0xFFFFFFFF));
if(value != (E1000_READ_REG(&adapter->hw, STATUS) & (0xFFFFF833))) {
*data = 1;
return 1;
}
REG_PATTERN_TEST(FCAL, 0xFFFFFFFF, 0xFFFFFFFF);
REG_PATTERN_TEST(FCAH, 0x0000FFFF, 0xFFFFFFFF);
REG_PATTERN_TEST(FCT, 0x0000FFFF, 0xFFFFFFFF);
REG_PATTERN_TEST(VET, 0x0000FFFF, 0xFFFFFFFF);
REG_PATTERN_TEST(RDTR, 0x0000FFFF, 0xFFFFFFFF);
REG_PATTERN_TEST(RDBAH, 0xFFFFFFFF, 0xFFFFFFFF);
REG_PATTERN_TEST(RDLEN, 0x000FFF80, 0x000FFFFF);
REG_PATTERN_TEST(RDH, 0x0000FFFF, 0x0000FFFF);
REG_PATTERN_TEST(RDT, 0x0000FFFF, 0x0000FFFF);
REG_PATTERN_TEST(FCRTH, 0x0000FFF8, 0x0000FFF8);
REG_PATTERN_TEST(FCTTV, 0x0000FFFF, 0x0000FFFF);
REG_PATTERN_TEST(TIPG, 0x3FFFFFFF, 0x3FFFFFFF);
REG_PATTERN_TEST(TDBAH, 0xFFFFFFFF, 0xFFFFFFFF);
REG_PATTERN_TEST(TDLEN, 0x000FFF80, 0x000FFFFF);
REG_SET_AND_CHECK(RCTL, 0xFFFFFFFF, 0x00000000);
REG_SET_AND_CHECK(RCTL, 0x06DFB3FE, 0x003FFFFB);
REG_SET_AND_CHECK(TCTL, 0xFFFFFFFF, 0x00000000);
if(adapter->hw.mac_type >= e1000_82543) {
REG_SET_AND_CHECK(RCTL, 0x06DFB3FE, 0xFFFFFFFF);
REG_PATTERN_TEST(RDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
REG_PATTERN_TEST(TXCW, 0xC000FFFF, 0x0000FFFF);
REG_PATTERN_TEST(TDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
REG_PATTERN_TEST(TIDV, 0x0000FFFF, 0x0000FFFF);
for(i = 0; i < E1000_RAR_ENTRIES; i++) {
REG_PATTERN_TEST(RA + ((i << 1) << 2), 0xFFFFFFFF,
0xFFFFFFFF);
REG_PATTERN_TEST(RA + (((i << 1) + 1) << 2), 0x8003FFFF,
0xFFFFFFFF);
}
} else {
REG_SET_AND_CHECK(RCTL, 0xFFFFFFFF, 0x01FFFFFF);
REG_PATTERN_TEST(RDBAL, 0xFFFFF000, 0xFFFFFFFF);
REG_PATTERN_TEST(TXCW, 0x0000FFFF, 0x0000FFFF);
REG_PATTERN_TEST(TDBAL, 0xFFFFF000, 0xFFFFFFFF);
}
for(i = 0; i < E1000_MC_TBL_SIZE; i++)
REG_PATTERN_TEST(MTA + (i << 2), 0xFFFFFFFF, 0xFFFFFFFF);
return 0;
}
static int
e1000_eeprom_test(struct e1000_adapter *adapter, uint64_t *data)
{
uint16_t temp;
uint16_t checksum = 0;
uint16_t i;
*data = 0;
/* Read and add up the contents of the EEPROM */
for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
if((e1000_read_eeprom(&adapter->hw, i, 1, &temp)) < 0) {
*data = 1;
break;
}
checksum += temp;
}
/* If Checksum is not Correct return error else test passed */
if((checksum != (uint16_t) EEPROM_SUM) && !(*data))
*data = 2;
return *data;
}
static irqreturn_t
e1000_test_intr(int irq,
void *data,
struct pt_regs *regs)
{
struct net_device *netdev = (struct net_device *) data;
struct e1000_adapter *adapter = netdev->priv;
adapter->test_icr |= E1000_READ_REG(&adapter->hw, ICR);
return IRQ_HANDLED;
}
static int
e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data)
{
struct net_device *netdev = adapter->netdev;
uint32_t icr, mask, i=0;
*data = 0;
/* Hook up test interrupt handler just for this test */
if(request_irq
(netdev->irq, &e1000_test_intr, SA_SHIRQ, netdev->name, netdev)) {
*data = 1;
return -1;
}
/* Disable all the interrupts */
E1000_WRITE_REG(&adapter->hw, IMC, 0xFFFFFFFF);
msec_delay(10);
/* Interrupts are disabled, so read interrupt cause
* register (icr) twice to verify that there are no interrupts
* pending. icr is clear on read.
*/
icr = E1000_READ_REG(&adapter->hw, ICR);
icr = E1000_READ_REG(&adapter->hw, ICR);
if(icr != 0) {
/* if icr is non-zero, there is no point
* running other interrupt tests.
*/
*data = 2;
i = 10;
}
/* Test each interrupt */
for(; i < 10; i++) {
/* Interrupt to test */
mask = 1 << i;
/* Disable the interrupt to be reported in
* the cause register and then force the same
* interrupt and see if one gets posted. If
* an interrupt was posted to the bus, the
* test failed.
*/
adapter->test_icr = 0;
E1000_WRITE_REG(&adapter->hw, IMC, mask);
E1000_WRITE_REG(&adapter->hw, ICS, mask);
msec_delay(10);
if(adapter->test_icr & mask) {
*data = 3;
break;
}
/* Enable the interrupt to be reported in
* the cause register and then force the same
* interrupt and see if one gets posted. If
* an interrupt was not posted to the bus, the
* test failed.
*/
adapter->test_icr = 0;
E1000_WRITE_REG(&adapter->hw, IMS, mask);
E1000_WRITE_REG(&adapter->hw, ICS, mask);
msec_delay(10);
if(!(adapter->test_icr & mask)) {
*data = 4;
break;
}
/* Disable the other interrupts to be reported in
* the cause register and then force the other
* interrupts and see if any get posted. If
* an interrupt was posted to the bus, the
* test failed.
*/
adapter->test_icr = 0;
E1000_WRITE_REG(&adapter->hw, IMC, ~mask);
E1000_WRITE_REG(&adapter->hw, ICS, ~mask);
msec_delay(10);
if(adapter->test_icr) {
*data = 5;
break;
}
}
/* Disable all the interrupts */
E1000_WRITE_REG(&adapter->hw, IMC, 0xFFFFFFFF);
msec_delay(10);
/* Unhook test interrupt handler */
free_irq(netdev->irq, netdev);
return *data;
}
static void
e1000_free_desc_rings(struct e1000_adapter *adapter)
{
struct e1000_desc_ring *txdr = &adapter->test_tx_ring;
struct e1000_desc_ring *rxdr = &adapter->test_rx_ring;
struct pci_dev *pdev = adapter->pdev;
int i;
if(txdr->desc && txdr->buffer_info) {
for(i = 0; i < txdr->count; i++) {
if(txdr->buffer_info[i].dma)
pci_unmap_single(pdev, txdr->buffer_info[i].dma,
txdr->buffer_info[i].length,
PCI_DMA_TODEVICE);
if(txdr->buffer_info[i].skb)
dev_kfree_skb(txdr->buffer_info[i].skb);
}
}
if(rxdr->desc && rxdr->buffer_info) {
for(i = 0; i < rxdr->count; i++) {
if(rxdr->buffer_info[i].dma)
pci_unmap_single(pdev, rxdr->buffer_info[i].dma,
rxdr->buffer_info[i].length,
PCI_DMA_FROMDEVICE);
if(rxdr->buffer_info[i].skb)
dev_kfree_skb(rxdr->buffer_info[i].skb);
}
}
if(txdr->desc)
pci_free_consistent(pdev, txdr->size, txdr->desc, txdr->dma);
if(rxdr->desc)
pci_free_consistent(pdev, rxdr->size, rxdr->desc, rxdr->dma);
if(txdr->buffer_info)
kfree(txdr->buffer_info);
if(rxdr->buffer_info)
kfree(rxdr->buffer_info);
return;
}
static int
e1000_setup_desc_rings(struct e1000_adapter *adapter)
{
struct e1000_desc_ring *txdr = &adapter->test_tx_ring;
struct e1000_desc_ring *rxdr = &adapter->test_rx_ring;
struct pci_dev *pdev = adapter->pdev;
uint32_t rctl;
int size, i, ret_val;
/* Setup Tx descriptor ring and Tx buffers */
txdr->count = 80;
size = txdr->count * sizeof(struct e1000_buffer);
if(!(txdr->buffer_info = kmalloc(size, GFP_KERNEL))) {
ret_val = 1;
goto err_nomem;
}
memset(txdr->buffer_info, 0, size);
txdr->size = txdr->count * sizeof(struct e1000_tx_desc);
E1000_ROUNDUP(txdr->size, 4096);
if(!(txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma))) {
ret_val = 2;
goto err_nomem;
}
memset(txdr->desc, 0, txdr->size);
txdr->next_to_use = txdr->next_to_clean = 0;
E1000_WRITE_REG(&adapter->hw, TDBAL,
((uint64_t) txdr->dma & 0x00000000FFFFFFFF));
E1000_WRITE_REG(&adapter->hw, TDBAH, ((uint64_t) txdr->dma >> 32));
E1000_WRITE_REG(&adapter->hw, TDLEN,
txdr->count * sizeof(struct e1000_tx_desc));
E1000_WRITE_REG(&adapter->hw, TDH, 0);
E1000_WRITE_REG(&adapter->hw, TDT, 0);
E1000_WRITE_REG(&adapter->hw, TCTL,
E1000_TCTL_PSP | E1000_TCTL_EN |
E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT |
E1000_FDX_COLLISION_DISTANCE << E1000_COLD_SHIFT);
for(i = 0; i < txdr->count; i++) {
struct e1000_tx_desc *tx_desc = E1000_TX_DESC(*txdr, i);
struct sk_buff *skb;
unsigned int size = 1024;
if(!(skb = alloc_skb(size, GFP_KERNEL))) {
ret_val = 3;
goto err_nomem;
}
skb_put(skb, size);
txdr->buffer_info[i].skb = skb;
txdr->buffer_info[i].length = skb->len;
txdr->buffer_info[i].dma =
pci_map_single(pdev, skb->data, skb->len,
PCI_DMA_TODEVICE);
tx_desc->buffer_addr = cpu_to_le64(txdr->buffer_info[i].dma);
tx_desc->lower.data = cpu_to_le32(skb->len);
tx_desc->lower.data |= E1000_TXD_CMD_EOP;
tx_desc->lower.data |= E1000_TXD_CMD_IFCS;
tx_desc->lower.data |= E1000_TXD_CMD_RPS;
tx_desc->upper.data = 0;
}
/* Setup Rx descriptor ring and Rx buffers */
rxdr->count = 80;
size = rxdr->count * sizeof(struct e1000_buffer);
if(!(rxdr->buffer_info = kmalloc(size, GFP_KERNEL))) {
ret_val = 4;
goto err_nomem;
}
memset(rxdr->buffer_info, 0, size);
rxdr->size = rxdr->count * sizeof(struct e1000_rx_desc);
if(!(rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma))) {
ret_val = 5;
goto err_nomem;
}
memset(rxdr->desc, 0, rxdr->size);
rxdr->next_to_use = rxdr->next_to_clean = 0;
rctl = E1000_READ_REG(&adapter->hw, RCTL);
E1000_WRITE_REG(&adapter->hw, RCTL, rctl & ~E1000_RCTL_EN);
E1000_WRITE_REG(&adapter->hw, RDBAL,
((uint64_t) rxdr->dma & 0xFFFFFFFF));
E1000_WRITE_REG(&adapter->hw, RDBAH, ((uint64_t) rxdr->dma >> 32));
E1000_WRITE_REG(&adapter->hw, RDLEN, rxdr->size);
E1000_WRITE_REG(&adapter->hw, RDH, 0);
E1000_WRITE_REG(&adapter->hw, RDT, 0);
rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 |
E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
(adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT);
E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
for(i = 0; i < rxdr->count; i++) {
struct e1000_rx_desc *rx_desc = E1000_RX_DESC(*rxdr, i);
struct sk_buff *skb;
if(!(skb = alloc_skb(E1000_RXBUFFER_2048 + 2, GFP_KERNEL))) {
ret_val = 6;
goto err_nomem;
}
skb_reserve(skb, 2);
rxdr->buffer_info[i].skb = skb;
rxdr->buffer_info[i].length = E1000_RXBUFFER_2048;
rxdr->buffer_info[i].dma =
pci_map_single(pdev, skb->data, E1000_RXBUFFER_2048,
PCI_DMA_FROMDEVICE);
rx_desc->buffer_addr = cpu_to_le64(rxdr->buffer_info[i].dma);
memset(skb->data, 0x00, skb->len);
}
return 0;
err_nomem:
e1000_free_desc_rings(adapter);
return ret_val;
}
static void
e1000_phy_disable_receiver(struct e1000_adapter *adapter)
{
/* Write out to PHY registers 29 and 30 to disable the Receiver. */
e1000_write_phy_reg(&adapter->hw, 29, 0x001F);
e1000_write_phy_reg(&adapter->hw, 30, 0x8FFC);
e1000_write_phy_reg(&adapter->hw, 29, 0x001A);
e1000_write_phy_reg(&adapter->hw, 30, 0x8FF0);
return;
}
static void
e1000_phy_reset_clk_and_crs(struct e1000_adapter *adapter)
{
uint16_t phy_reg;
/* Because we reset the PHY above, we need to re-force TX_CLK in the
* Extended PHY Specific Control Register to 25MHz clock. This
* value defaults back to a 2.5MHz clock when the PHY is reset.
*/
e1000_read_phy_reg(&adapter->hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_reg);
phy_reg |= M88E1000_EPSCR_TX_CLK_25;
e1000_write_phy_reg(&adapter->hw,
M88E1000_EXT_PHY_SPEC_CTRL, phy_reg);
/* In addition, because of the s/w reset above, we need to enable
* CRS on TX. This must be set for both full and half duplex
* operation.
*/
e1000_read_phy_reg(&adapter->hw, M88E1000_PHY_SPEC_CTRL, &phy_reg);
phy_reg |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
e1000_write_phy_reg(&adapter->hw,
M88E1000_PHY_SPEC_CTRL, phy_reg);
}
static int
e1000_nonintegrated_phy_loopback(struct e1000_adapter *adapter)
{
uint32_t ctrl_reg;
uint16_t phy_reg;
/* Setup the Device Control Register for PHY loopback test. */
ctrl_reg = E1000_READ_REG(&adapter->hw, CTRL);
ctrl_reg |= (E1000_CTRL_ILOS | /* Invert Loss-Of-Signal */
E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
E1000_CTRL_SPD_1000 | /* Force Speed to 1000 */
E1000_CTRL_FD); /* Force Duplex to FULL */
E1000_WRITE_REG(&adapter->hw, CTRL, ctrl_reg);
/* Read the PHY Specific Control Register (0x10) */
e1000_read_phy_reg(&adapter->hw, M88E1000_PHY_SPEC_CTRL, &phy_reg);
/* Clear Auto-Crossover bits in PHY Specific Control Register
* (bits 6:5).
*/
phy_reg &= ~M88E1000_PSCR_AUTO_X_MODE;
e1000_write_phy_reg(&adapter->hw, M88E1000_PHY_SPEC_CTRL, phy_reg);
/* Perform software reset on the PHY */
e1000_phy_reset(&adapter->hw);
/* Have to setup TX_CLK and TX_CRS after software reset */
e1000_phy_reset_clk_and_crs(adapter);
e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x8100);
/* Wait for reset to complete. */
udelay(500);
/* Have to setup TX_CLK and TX_CRS after software reset */
e1000_phy_reset_clk_and_crs(adapter);
/* Write out to PHY registers 29 and 30 to disable the Receiver. */
e1000_phy_disable_receiver(adapter);
/* Set the loopback bit in the PHY control register. */
e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg);
phy_reg |= MII_CR_LOOPBACK;
e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_reg);
/* Setup TX_CLK and TX_CRS one more time. */
e1000_phy_reset_clk_and_crs(adapter);
/* Check Phy Configuration */
e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg);
if(phy_reg != 0x4100)
return 9;
e1000_read_phy_reg(&adapter->hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_reg);
if(phy_reg != 0x0070)
return 10;
e1000_read_phy_reg(&adapter->hw, 29, &phy_reg);
if(phy_reg != 0x001A)
return 11;
return 0;
}
static int
e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
{
uint32_t ctrl_reg = 0;
uint32_t stat_reg = 0;
adapter->hw.autoneg = FALSE;
if(adapter->hw.phy_type == e1000_phy_m88) {
/* Auto-MDI/MDIX Off */
e1000_write_phy_reg(&adapter->hw,
M88E1000_PHY_SPEC_CTRL, 0x0808);
/* reset to update Auto-MDI/MDIX */
e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x9140);
/* autoneg off */
e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x8140);
}
/* force 1000, set loopback */
e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x4140);
/* Now set up the MAC to the same speed/duplex as the PHY. */
ctrl_reg = E1000_READ_REG(&adapter->hw, CTRL);
ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */
E1000_CTRL_FD); /* Force Duplex to FULL */
if(adapter->hw.media_type == e1000_media_type_copper &&
adapter->hw.phy_type == e1000_phy_m88) {
ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */
} else {
/* Set the ILOS bit on the fiber Nic is half
* duplex link is detected. */
stat_reg = E1000_READ_REG(&adapter->hw, STATUS);
if((stat_reg & E1000_STATUS_FD) == 0)
ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU);
}
E1000_WRITE_REG(&adapter->hw, CTRL, ctrl_reg);
/* Disable the receiver on the PHY so when a cable is plugged in, the
* PHY does not begin to autoneg when a cable is reconnected to the NIC.
*/
if(adapter->hw.phy_type == e1000_phy_m88)
e1000_phy_disable_receiver(adapter);
udelay(500);
return 0;
}
static int
e1000_set_phy_loopback(struct e1000_adapter *adapter)
{
uint16_t phy_reg = 0;
uint16_t count = 0;
switch (adapter->hw.mac_type) {
case e1000_82543:
if(adapter->hw.media_type == e1000_media_type_copper) {
/* Attempt to setup Loopback mode on Non-integrated PHY.
* Some PHY registers get corrupted at random, so
* attempt this 10 times.
*/
while(e1000_nonintegrated_phy_loopback(adapter) &&
count++ < 10);
if(count < 11)
return 0;
}
break;
case e1000_82544:
case e1000_82540:
case e1000_82545:
case e1000_82546:
case e1000_82541:
case e1000_82547:
return e1000_integrated_phy_loopback(adapter);
break;
default:
/* Default PHY loopback work is to read the MII
* control register and assert bit 14 (loopback mode).
*/
e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg);
phy_reg |= MII_CR_LOOPBACK;
e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_reg);
return 0;
break;
}
return 8;
}
static int
e1000_setup_loopback_test(struct e1000_adapter *adapter)
{
uint32_t rctl;
if(adapter->hw.media_type == e1000_media_type_fiber) {
if(adapter->hw.mac_type == e1000_82545 ||
adapter->hw.mac_type == e1000_82546)
return e1000_set_phy_loopback(adapter);
else {
rctl = E1000_READ_REG(&adapter->hw, RCTL);
rctl |= E1000_RCTL_LBM_TCVR;
E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
return 0;
}
} else if(adapter->hw.media_type == e1000_media_type_copper)
return e1000_set_phy_loopback(adapter);
return 7;
}
static void
e1000_loopback_cleanup(struct e1000_adapter *adapter)
{
uint32_t rctl;
uint16_t phy_reg;
rctl = E1000_READ_REG(&adapter->hw, RCTL);
rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC);
E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
if(adapter->hw.media_type == e1000_media_type_copper ||
(adapter->hw.media_type == e1000_media_type_fiber &&
(adapter->hw.mac_type == e1000_82545 ||
adapter->hw.mac_type == e1000_82546))) {
adapter->hw.autoneg = TRUE;
e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg);
if(phy_reg & MII_CR_LOOPBACK) {
phy_reg &= ~MII_CR_LOOPBACK;
e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_reg);
e1000_phy_reset(&adapter->hw);
}
}
}
static void
e1000_create_lbtest_frame(struct sk_buff *skb, unsigned int frame_size)
{
memset(skb->data, 0xFF, frame_size);
frame_size = (frame_size % 2) ? (frame_size - 1) : frame_size;
memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1);
memset(&skb->data[frame_size / 2 + 10], 0xBE, 1);
memset(&skb->data[frame_size / 2 + 12], 0xAF, 1);
}
static int
e1000_check_lbtest_frame(struct sk_buff *skb, unsigned int frame_size)
{
frame_size = (frame_size % 2) ? (frame_size - 1) : frame_size;
if(*(skb->data + 3) == 0xFF) {
if((*(skb->data + frame_size / 2 + 10) == 0xBE) &&
(*(skb->data + frame_size / 2 + 12) == 0xAF)) {
return 0;
}
}
return 13;
}
static int
e1000_run_loopback_test(struct e1000_adapter *adapter)
{
struct e1000_desc_ring *txdr = &adapter->test_tx_ring;
struct e1000_desc_ring *rxdr = &adapter->test_rx_ring;
struct pci_dev *pdev = adapter->pdev;
int i;
E1000_WRITE_REG(&adapter->hw, RDT, rxdr->count - 1);
for(i = 0; i < 64; i++) {
e1000_create_lbtest_frame(txdr->buffer_info[i].skb, 1024);
pci_dma_sync_single(pdev, txdr->buffer_info[i].dma,
txdr->buffer_info[i].length,
PCI_DMA_TODEVICE);
}
E1000_WRITE_REG(&adapter->hw, TDT, i);
msec_delay(200);
pci_dma_sync_single(pdev, rxdr->buffer_info[0].dma,
rxdr->buffer_info[0].length, PCI_DMA_FROMDEVICE);
return e1000_check_lbtest_frame(rxdr->buffer_info[0].skb, 1024);
}
static int
e1000_loopback_test(struct e1000_adapter *adapter, uint64_t *data)
{
if((*data = e1000_setup_desc_rings(adapter))) goto err_loopback;
if((*data = e1000_setup_loopback_test(adapter))) goto err_loopback;
*data = e1000_run_loopback_test(adapter);
e1000_loopback_cleanup(adapter);
e1000_free_desc_rings(adapter);
err_loopback:
return *data;
}
static int
e1000_link_test(struct e1000_adapter *adapter, uint64_t *data)
{
*data = 0;
e1000_check_for_link(&adapter->hw);
if(!(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU)) {
*data = 1;
}
return *data;
}
static int
e1000_ethtool_test(struct e1000_adapter *adapter,
struct ethtool_test *eth_test, uint64_t *data)
{
boolean_t if_running = netif_running(adapter->netdev);
if(eth_test->flags == ETH_TEST_FL_OFFLINE) {
/* Offline tests */
/* Link test performed before hardware reset so autoneg doesn't
* interfere with test result */
if(e1000_link_test(adapter, &data[4]))
eth_test->flags |= ETH_TEST_FL_FAILED;
if(if_running)
e1000_down(adapter);
e1000_reset(adapter);
if(e1000_reg_test(adapter, &data[0]))
eth_test->flags |= ETH_TEST_FL_FAILED;
e1000_reset(adapter);
if(e1000_eeprom_test(adapter, &data[1]))
eth_test->flags |= ETH_TEST_FL_FAILED;
e1000_reset(adapter);
if(e1000_intr_test(adapter, &data[2]))
eth_test->flags |= ETH_TEST_FL_FAILED;
e1000_reset(adapter);
if(e1000_loopback_test(adapter, &data[3]))
eth_test->flags |= ETH_TEST_FL_FAILED;
e1000_reset(adapter);
if(if_running)
e1000_up(adapter);
} else {
/* Online tests */
if(e1000_link_test(adapter, &data[4]))
eth_test->flags |= ETH_TEST_FL_FAILED;
/* Offline tests aren't run; pass by default */
data[0] = 0;
data[1] = 0;
data[2] = 0;
data[3] = 0;
}
return 0;
}
static void
e1000_ethtool_gwol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol)
{
......@@ -443,24 +1305,46 @@ e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr)
case ETHTOOL_GSTRINGS: {
struct ethtool_gstrings gstrings = { ETHTOOL_GSTRINGS };
char *strings = NULL;
int err = 0;
if(copy_from_user(&gstrings, addr, sizeof(gstrings)))
return -EFAULT;
switch(gstrings.string_set) {
case ETH_SS_STATS:
case ETH_SS_TEST:
gstrings.len = E1000_TEST_LEN;
strings = kmalloc(E1000_TEST_LEN * ETH_GSTRING_LEN,
GFP_KERNEL);
if(!strings)
return -ENOMEM;
memcpy(strings, e1000_gstrings_test, E1000_TEST_LEN *
ETH_GSTRING_LEN);
break;
case ETH_SS_STATS: {
int i;
gstrings.len = E1000_STATS_LEN;
strings = *e1000_gstrings_stats;
strings = kmalloc(E1000_STATS_LEN * ETH_GSTRING_LEN,
GFP_KERNEL);
if(!strings)
return -ENOMEM;
for(i=0; i < E1000_STATS_LEN; i++) {
memcpy(&strings[i * ETH_GSTRING_LEN],
e1000_gstrings_stats[i].stat_string,
ETH_GSTRING_LEN);
}
break;
}
default:
return -EOPNOTSUPP;
}
if(copy_to_user(addr, &gstrings, sizeof(gstrings)))
return -EFAULT;
err = -EFAULT;
addr += offsetof(struct ethtool_gstrings, data);
if(copy_to_user(addr, strings,
if(!err && copy_to_user(addr, strings,
gstrings.len * ETH_GSTRING_LEN))
return -EFAULT;
return 0;
err = -EFAULT;
kfree(strings);
return err;
}
case ETHTOOL_GREGS: {
struct ethtool_regs regs = {ETHTOOL_GREGS};
......@@ -522,16 +1406,14 @@ e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr)
void *ptr;
int err = 0;
if(copy_from_user(&eeprom, addr, sizeof(eeprom)))
return -EFAULT;
eeprom_buff = kmalloc(hw->eeprom.word_size * 2, GFP_KERNEL);
if(eeprom_buff == NULL)
if(!eeprom_buff)
return -ENOMEM;
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;
......@@ -565,18 +1447,45 @@ e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr)
}
case ETHTOOL_GSTATS: {
struct {
struct ethtool_stats cmd;
struct ethtool_stats eth_stats;
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];
stats.data[i] = (e1000_gstrings_stats[i].sizeof_stat ==
sizeof(uint64_t)) ?
*(uint64_t *)((char *)adapter +
e1000_gstrings_stats[i].stat_offset) :
*(uint32_t *)((char *)adapter +
e1000_gstrings_stats[i].stat_offset);
if(copy_to_user(addr, &stats, sizeof(stats)))
return -EFAULT;
return 0;
}
case ETHTOOL_TEST: {
struct {
struct ethtool_test eth_test;
uint64_t data[E1000_TEST_LEN];
} test = { {ETHTOOL_TEST} };
int err;
if(!capable(CAP_NET_ADMIN))
return -EPERM;
if(copy_from_user(&test.eth_test, addr, sizeof(test.eth_test)))
return -EFAULT;
test.eth_test.len = E1000_TEST_LEN;
if((err = e1000_ethtool_test(adapter, &test.eth_test,
test.data)))
return err;
if(copy_to_user(addr, &test, sizeof(test)) != 0)
return -EFAULT;
return 0;
}
default:
return -EOPNOTSUPP;
}
......
......@@ -185,6 +185,7 @@ e1000_set_mac_type(struct e1000_hw *hw)
break;
case E1000_DEV_ID_82546EB_COPPER:
case E1000_DEV_ID_82546EB_FIBER:
case E1000_DEV_ID_82546EB_QUAD_COPPER:
hw->mac_type = e1000_82546;
break;
case E1000_DEV_ID_82541EI:
......@@ -288,9 +289,7 @@ e1000_reset_hw(struct e1000_hw *hw)
/* Configure activity LED after PHY reset */
led_ctrl = E1000_READ_REG(hw, LEDCTL);
led_ctrl &= IGP_ACTIVITY_LED_MASK;
led_ctrl |= IGP_ACTIVITY_LED_ENABLE;
if(hw->mac_type == e1000_82547)
led_ctrl |= IGP_LED3_MODE;
led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
}
......@@ -737,9 +736,7 @@ e1000_setup_copper_link(struct e1000_hw *hw)
/* Configure activity LED after PHY reset */
led_ctrl = E1000_READ_REG(hw, LEDCTL);
led_ctrl &= IGP_ACTIVITY_LED_MASK;
led_ctrl |= IGP_ACTIVITY_LED_ENABLE;
if(hw->mac_type == e1000_82547)
led_ctrl |= IGP_LED3_MODE;
led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
if(hw->autoneg_advertised == ADVERTISE_1000_FULL) {
......@@ -2293,9 +2290,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
/* Configure activity LED after PHY reset */
led_ctrl = E1000_READ_REG(hw, LEDCTL);
led_ctrl &= IGP_ACTIVITY_LED_MASK;
led_ctrl |= IGP_ACTIVITY_LED_ENABLE;
if(hw->mac_type == e1000_82547)
led_ctrl |= IGP_LED3_MODE;
led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
}
}
......@@ -3801,6 +3796,7 @@ e1000_setup_led(struct e1000_hw *hw)
case E1000_DEV_ID_82540EM_LOM:
case E1000_DEV_ID_82545EM_COPPER:
case E1000_DEV_ID_82546EB_COPPER:
case E1000_DEV_ID_82546EB_QUAD_COPPER:
case E1000_DEV_ID_82541EI:
case E1000_DEV_ID_82541EP:
case E1000_DEV_ID_82547EI:
......@@ -3842,6 +3838,7 @@ e1000_cleanup_led(struct e1000_hw *hw)
case E1000_DEV_ID_82545EM_FIBER:
case E1000_DEV_ID_82546EB_COPPER:
case E1000_DEV_ID_82546EB_FIBER:
case E1000_DEV_ID_82546EB_QUAD_COPPER:
case E1000_DEV_ID_82541EI:
case E1000_DEV_ID_82541EP:
case E1000_DEV_ID_82547EI:
......@@ -3896,6 +3893,7 @@ e1000_led_on(struct e1000_hw *hw)
case E1000_DEV_ID_82540EM_LOM:
case E1000_DEV_ID_82545EM_COPPER:
case E1000_DEV_ID_82546EB_COPPER:
case E1000_DEV_ID_82546EB_QUAD_COPPER:
case E1000_DEV_ID_82541EI:
case E1000_DEV_ID_82541EP:
case E1000_DEV_ID_82547EI:
......@@ -3949,6 +3947,7 @@ e1000_led_off(struct e1000_hw *hw)
case E1000_DEV_ID_82540EM_LOM:
case E1000_DEV_ID_82545EM_COPPER:
case E1000_DEV_ID_82546EB_COPPER:
case E1000_DEV_ID_82546EB_QUAD_COPPER:
case E1000_DEV_ID_82541EI:
case E1000_DEV_ID_82541EP:
case E1000_DEV_ID_82547EI:
......@@ -4206,7 +4205,11 @@ e1000_get_bus_info(struct e1000_hw *hw)
status = E1000_READ_REG(hw, STATUS);
hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ?
e1000_bus_type_pcix : e1000_bus_type_pci;
if(hw->bus_type == e1000_bus_type_pci) {
if(hw->device_id == E1000_DEV_ID_82546EB_QUAD_COPPER) {
hw->bus_speed = (hw->bus_type == e1000_bus_type_pci) ?
e1000_bus_speed_66 : e1000_bus_speed_120;
} else if(hw->bus_type == e1000_bus_type_pci) {
hw->bus_speed = (status & E1000_STATUS_PCI66) ?
e1000_bus_speed_66 : e1000_bus_speed_33;
} else {
......
......@@ -99,6 +99,7 @@ typedef enum {
e1000_bus_speed_33,
e1000_bus_speed_66,
e1000_bus_speed_100,
e1000_bus_speed_120,
e1000_bus_speed_133,
e1000_bus_speed_reserved
} e1000_bus_speed;
......@@ -314,10 +315,11 @@ void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value);
#define E1000_DEV_ID_82545EM_FIBER 0x1011
#define E1000_DEV_ID_82546EB_COPPER 0x1010
#define E1000_DEV_ID_82546EB_FIBER 0x1012
#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D
#define E1000_DEV_ID_82541EI 0x1013
#define E1000_DEV_ID_82541EP 0x1018
#define E1000_DEV_ID_82547EI 0x1019
#define NUM_DEV_IDS 19
#define NUM_DEV_IDS 20
#define NODE_ADDRESS_SIZE 6
#define ETH_LENGTH_OF_ADDRESS 6
......@@ -601,7 +603,7 @@ struct e1000_ffvt_entry {
#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */
#define E1000_EERD 0x00014 /* EEPROM Read - RW */
#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */
#define E1000_FLA 0x0001C /* Flash Access Register - RW */
#define E1000_FLA 0x0001C /* Flash Access - RW */
#define E1000_MDIC 0x00020 /* MDI Control - RW */
#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */
#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */
......@@ -730,6 +732,7 @@ struct e1000_ffvt_entry {
* the registers function in the same manner.
*/
#define E1000_82542_CTRL E1000_CTRL
#define E1000_82542_CTRL_DUP E1000_CTRL_DUP
#define E1000_82542_STATUS E1000_STATUS
#define E1000_82542_EECD E1000_EECD
#define E1000_82542_EERD E1000_EERD
......@@ -1485,7 +1488,6 @@ struct e1000_hw {
#define E1000_COLLISION_DISTANCE 64
#define E1000_FDX_COLLISION_DISTANCE E1000_COLLISION_DISTANCE
#define E1000_HDX_COLLISION_DISTANCE E1000_COLLISION_DISTANCE
#define E1000_GB_HDX_COLLISION_DISTANCE 512
#define E1000_COLD_SHIFT 12
/* The number of Transmit and Receive Descriptors must be a multiple of 8 */
......
......@@ -30,7 +30,14 @@
/* Change Log
*
* 5.0.43 3/5/03
* 5.1.11 5/6/03
* o Feature: Added support for 82546EB (Quad-port) hardware.
* o Feature: Added support for Diagnostics through Ethtool.
* o Cleanup: Removed /proc support.
* o Cleanup: Removed proprietary IDIAG interface.
* o Bug fix: TSO bug fixes.
*
* 5.0.42 3/5/03
* o Feature: Added support for 82541 and 82547 hardware.
* o Feature: Added support for Intel Gigabit PHY (IGP) and a variety of
* eeproms.
......@@ -46,51 +53,22 @@
* shared interrupt instances.
*
* 4.4.18 11/27/02
* o Feature: Added user-settable knob for interrupt throttle rate (ITR).
* o Cleanup: removed large static array allocations.
* o Cleanup: C99 struct initializer format.
* o Bug fix: restore VLAN settings when interface is brought up.
* o Bug fix: return cleanly in probe if error in detecting MAC type.
* o Bug fix: Wake up on magic packet by default only if enabled in eeprom.
* o Bug fix: Validate MAC address in set_mac.
* o Bug fix: Throw away zero-length Tx skbs.
* o Bug fix: Make ethtool EEPROM acceses work on older versions of ethtool.
*
* 4.4.12 10/15/02
*/
char e1000_driver_name[] = "e1000";
char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
char e1000_driver_version[] = "5.0.43-k3";
char e1000_driver_version[] = "5.1.11-k1";
char e1000_copyright[] = "Copyright (c) 1999-2003 Intel Corporation.";
/* e1000_pci_tbl - PCI Device ID Table
*
* Private driver_data field (last one) stores an index into e1000_strings
* Wildcard entries (PCI_ANY_ID) should come last
* Last entry must be all 0s
*
* { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
* Class, Class Mask, String Index }
* Class, Class Mask, private data (not used) }
*/
static struct pci_device_id e1000_pci_tbl[] __devinitdata = {
/* Intel(R) PRO/1000 Network Connection */
{0x8086, 0x1000, 0x8086, 0x1000, 0, 0, 0},
{0x8086, 0x1001, 0x8086, 0x1003, 0, 0, 0},
{0x8086, 0x1004, 0x8086, 0x1004, 0, 0, 0},
{0x8086, 0x1008, 0x8086, 0x1107, 0, 0, 0},
{0x8086, 0x1009, 0x8086, 0x1109, 0, 0, 0},
{0x8086, 0x100C, 0x8086, 0x1112, 0, 0, 0},
{0x8086, 0x100E, 0x8086, 0x001E, 0, 0, 0},
/* Compaq Gigabit Ethernet Server Adapter */
{0x8086, 0x1000, 0x0E11, PCI_ANY_ID, 0, 0, 1},
{0x8086, 0x1001, 0x0E11, PCI_ANY_ID, 0, 0, 1},
{0x8086, 0x1004, 0x0E11, PCI_ANY_ID, 0, 0, 1},
/* IBM Mobile, Desktop & Server Adapters */
{0x8086, 0x1000, 0x1014, PCI_ANY_ID, 0, 0, 2},
{0x8086, 0x1001, 0x1014, PCI_ANY_ID, 0, 0, 2},
{0x8086, 0x1004, 0x1014, PCI_ANY_ID, 0, 0, 2},
/* Generic */
{0x8086, 0x1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
......@@ -106,6 +84,7 @@ static struct pci_device_id e1000_pci_tbl[] __devinitdata = {
{0x8086, 0x1016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x1017, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x101E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x101D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x1013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x1019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
/* required last entry */
......@@ -114,12 +93,6 @@ static struct pci_device_id e1000_pci_tbl[] __devinitdata = {
MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
static char *e1000_strings[] = {
"Intel(R) PRO/1000 Network Connection",
"HP Gigabit Ethernet Server Adapter",
"IBM Mobile, Desktop & Server Adapters"
};
/* Local Function Prototypes */
int e1000_up(struct e1000_adapter *adapter);
......@@ -130,7 +103,7 @@ int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx);
static int e1000_init_module(void);
static void e1000_exit_module(void);
static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
static void e1000_remove(struct pci_dev *pdev);
static void __devexit e1000_remove(struct pci_dev *pdev);
static int e1000_sw_init(struct e1000_adapter *adapter);
static int e1000_open(struct net_device *netdev);
static int e1000_close(struct net_device *netdev);
......@@ -195,7 +168,6 @@ struct notifier_block e1000_notifier_reboot = {
.priority = 0
};
/* Exported from other modules */
extern void e1000_check_options(struct e1000_adapter *adapter);
......@@ -234,8 +206,9 @@ e1000_init_module(void)
printk(KERN_INFO "%s\n", e1000_copyright);
ret = pci_module_init(&e1000_driver);
if(ret >= 0)
if(ret >= 0) {
register_reboot_notifier(&e1000_notifier_reboot);
}
return ret;
}
......@@ -439,7 +412,6 @@ e1000_probe(struct pci_dev *pdev,
netdev->base_addr = adapter->hw.io_base;
adapter->bd_number = cards_found;
adapter->id_string = e1000_strings[ent->driver_data];
/* setup the private structure */
......@@ -500,15 +472,14 @@ e1000_probe(struct pci_dev *pdev,
(void (*)(void *))e1000_tx_timeout_task, netdev);
register_netdev(netdev);
memcpy(adapter->ifname, netdev->name, IFNAMSIZ);
adapter->ifname[IFNAMSIZ-1] = 0;
/* we're going to reset, so assume we have no link for now */
netif_carrier_off(netdev);
netif_stop_queue(netdev);
printk(KERN_INFO "%s: %s\n", netdev->name, adapter->id_string);
printk(KERN_INFO "%s: Intel(R) PRO/1000 Network Connection\n",
netdev->name);
e1000_check_options(adapter);
/* Initial Wake on LAN setting
......@@ -568,7 +539,6 @@ e1000_remove(struct pci_dev *pdev)
e1000_phy_hw_reset(&adapter->hw);
iounmap(adapter->hw.hw_addr);
pci_release_regions(pdev);
......@@ -831,8 +801,9 @@ e1000_configure_tx(struct e1000_adapter *adapter)
e1000_config_collision_dist(&adapter->hw);
/* Setup Transmit Descriptor Settings for this adapter */
adapter->txd_cmd = E1000_TXD_CMD_IFCS | E1000_TXD_CMD_IDE;
/* Setup Transmit Descriptor Settings for eop descriptor */
adapter->txd_cmd = E1000_TXD_CMD_IDE | E1000_TXD_CMD_EOP |
E1000_TXD_CMD_IFCS;
if(adapter->hw.report_tx_early == 1)
adapter->txd_cmd |= E1000_TXD_CMD_RS;
......@@ -1435,7 +1406,7 @@ e1000_watchdog(unsigned long data)
#define E1000_TX_FLAGS_VLAN_SHIFT 16
static inline boolean_t
e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb, int tx_flags)
e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb)
{
#ifdef NETIF_F_TSO
struct e1000_context_desc *context_desc;
......@@ -1471,7 +1442,7 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb, int tx_flags)
context_desc->upper_setup.tcp_fields.tucse = cpu_to_le16(tucse);
context_desc->tcp_seg_setup.fields.mss = cpu_to_le16(mss);
context_desc->tcp_seg_setup.fields.hdr_len = hdr_len;
context_desc->cmd_and_length = cpu_to_le32(adapter->txd_cmd |
context_desc->cmd_and_length = cpu_to_le32(
E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE |
E1000_TXD_CMD_IP | E1000_TXD_CMD_TCP |
(skb->len - (hdr_len)));
......@@ -1504,8 +1475,7 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
context_desc->upper_setup.tcp_fields.tucso = cso;
context_desc->upper_setup.tcp_fields.tucse = 0;
context_desc->tcp_seg_setup.data = 0;
context_desc->cmd_and_length =
cpu_to_le32(adapter->txd_cmd | E1000_TXD_CMD_DEXT);
context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT);
if(++i == adapter->tx_ring.count) i = 0;
adapter->tx_ring.next_to_use = i;
......@@ -1520,7 +1490,8 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
#define E1000_MAX_DATA_PER_TXD (1<<E1000_MAX_TXD_PWR)
static inline int
e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb)
e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb,
unsigned int first)
{
struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
int len = skb->len, offset = 0, size, count = 0, i;
......@@ -1588,6 +1559,7 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb)
}
if(--i < 0) i = tx_ring->count - 1;
tx_ring->buffer_info[i].skb = skb;
tx_ring->buffer_info[first].next_to_watch = i;
return count;
}
......@@ -1597,12 +1569,9 @@ e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags)
{
struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
struct e1000_tx_desc *tx_desc = NULL;
uint32_t txd_upper, txd_lower;
uint32_t txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS;
int i;
txd_upper = 0;
txd_lower = adapter->txd_cmd;
if(tx_flags & E1000_TX_FLAGS_TSO) {
txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D |
E1000_TXD_CMD_TSE;
......@@ -1630,7 +1599,7 @@ e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags)
if(++i == tx_ring->count) i = 0;
}
tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP);
tx_desc->lower.data |= cpu_to_le32(adapter->txd_cmd);
/* Force memory writes to complete before letting h/w
* know there are new descriptors to fetch. (Only
......@@ -1690,6 +1659,7 @@ static int
e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev->priv;
unsigned int first;
int tx_flags = 0;
if(skb->len <= 0) {
......@@ -1715,12 +1685,14 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT);
}
if(e1000_tso(adapter, skb, tx_flags))
first = adapter->tx_ring.next_to_use;
if(e1000_tso(adapter, skb))
tx_flags |= E1000_TX_FLAGS_TSO;
else if(e1000_tx_csum(adapter, skb))
tx_flags |= E1000_TX_FLAGS_CSUM;
e1000_tx_queue(adapter, e1000_tx_map(adapter, skb), tx_flags);
e1000_tx_queue(adapter, e1000_tx_map(adapter, skb, first), tx_flags);
netdev->trans_start = jiffies;
......@@ -1952,6 +1924,7 @@ e1000_update_stats(struct e1000_adapter *adapter)
}
if((hw->mac_type <= e1000_82546) &&
(hw->phy_type == e1000_phy_m88) &&
!e1000_read_phy_reg(hw, M88E1000_RX_ERR_CNTR, &phy_tmp))
adapter->phy_stats.receive_errors += phy_tmp;
}
......@@ -2069,39 +2042,47 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
struct e1000_tx_desc *tx_desc;
int i, cleaned = FALSE;
struct e1000_tx_desc *tx_desc, *eop_desc;
struct e1000_buffer *buffer_info;
int i, eop, cleaned = FALSE;
i = tx_ring->next_to_clean;
tx_desc = E1000_TX_DESC(*tx_ring, i);
eop = tx_ring->buffer_info[i].next_to_watch;
eop_desc = E1000_TX_DESC(*tx_ring, eop);
while(tx_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
while(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
cleaned = TRUE;
for(cleaned = FALSE; !cleaned; ) {
tx_desc = E1000_TX_DESC(*tx_ring, i);
buffer_info = &tx_ring->buffer_info[i];
if(tx_ring->buffer_info[i].dma) {
if(buffer_info->dma) {
pci_unmap_page(pdev,
tx_ring->buffer_info[i].dma,
tx_ring->buffer_info[i].length,
buffer_info->dma,
buffer_info->length,
PCI_DMA_TODEVICE);
tx_ring->buffer_info[i].dma = 0;
buffer_info->dma = 0;
}
if(tx_ring->buffer_info[i].skb) {
if(buffer_info->skb) {
dev_kfree_skb_any(tx_ring->buffer_info[i].skb);
dev_kfree_skb_any(buffer_info->skb);
tx_ring->buffer_info[i].skb = NULL;
buffer_info->skb = NULL;
}
tx_desc->buffer_addr = 0;
tx_desc->lower.data = 0;
tx_desc->upper.data = 0;
cleaned = (i == eop);
if(++i == tx_ring->count) i = 0;
tx_desc = E1000_TX_DESC(*tx_ring, i);
}
eop = tx_ring->buffer_info[i].next_to_watch;
eop_desc = E1000_TX_DESC(*tx_ring, eop);
}
tx_ring->next_to_clean = i;
......@@ -2224,7 +2205,6 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter)
netif_rx(skb);
}
#endif /* CONFIG_E1000_NAPI */
netdev->last_rx = jiffies;
rx_desc->status = 0;
......@@ -2677,7 +2657,6 @@ e1000_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
return NOTIFY_DONE;
}
static int
e1000_suspend(struct pci_dev *pdev, uint32_t state)
{
......
......@@ -134,7 +134,7 @@ clone_list[] __initdata = {
{0,}
};
static void tachyon_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t tachyon_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void tachyon_interrupt_handler(int irq, void* dev_id, struct pt_regs* regs);
static int initialize_register_pointers(struct fc_info *fi);
......@@ -623,7 +623,7 @@ u_int bus_addr, bus_indx_addr, i;
}
static void tachyon_interrupt(int irq, void* dev_id, struct pt_regs* regs)
static irqreturn_t tachyon_interrupt(int irq, void* dev_id, struct pt_regs* regs)
{
struct Scsi_Host *host = dev_id;
struct iph5526_hostdata *hostdata = (struct iph5526_hostdata *)host->hostdata;
......@@ -632,6 +632,7 @@ u_long flags;
spin_lock_irqsave(&fi->fc_lock, flags);
tachyon_interrupt_handler(irq, dev_id, regs);
spin_unlock_irqrestore(&fi->fc_lock, flags);
return IRQ_HANDLED;
}
static void tachyon_interrupt_handler(int irq, void* dev_id, struct pt_regs* regs)
......@@ -3720,12 +3721,13 @@ struct fc_info *fi = (struct fc_info*)dev->priv;
int iph5526_detect(Scsi_Host_Template *tmpt)
{
struct Scsi_Host *host = NULL;
struct iph5526_hostdata *hostdata;
struct fc_info *fi = NULL;
int no_of_hosts = 0, timeout, i, j, count = 0;
u_int pci_maddr = 0;
struct pci_dev *pdev = NULL;
struct Scsi_Host *host = NULL;
struct iph5526_hostdata *hostdata;
struct fc_info *fi = NULL;
int no_of_hosts = 0, i, j, count = 0;
u_int pci_maddr = 0;
struct pci_dev *pdev = NULL;
unsigned long timeout;
tmpt->proc_name = "iph5526";
if (pci_present() == 0) {
......
......@@ -188,7 +188,7 @@ struct fec_enet_private {
static int fec_enet_open(struct net_device *dev);
static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void fec_enet_mii(struct net_device *dev);
static void fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs);
static irqreturn_t fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs);
static void fec_enet_tx(struct net_device *dev);
static void fec_enet_rx(struct net_device *dev);
static int fec_enet_close(struct net_device *dev);
......@@ -393,12 +393,13 @@ fec_timeout(struct net_device *dev)
/* The interrupt handler.
* This is called from the MPC core interrupt.
*/
static void
static irqreturn_t
fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
{
struct net_device *dev = dev_id;
volatile fec_t *fecp;
uint int_events;
int handled = 0;
fecp = (volatile fec_t*)dev->base_addr;
......@@ -413,20 +414,27 @@ fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
/* Handle receive event in its own function.
*/
if (int_events & FEC_ENET_RXF)
if (int_events & FEC_ENET_RXF) {
handled = 1;
fec_enet_rx(dev);
}
/* Transmit OK, or non-fatal error. Update the buffer
descriptors. FEC handles all errors, we just discover
them as part of the transmit process.
*/
if (int_events & FEC_ENET_TXF)
if (int_events & FEC_ENET_TXF) {
handled = 1;
fec_enet_tx(dev);
}
if (int_events & FEC_ENET_MII)
if (int_events & FEC_ENET_MII) {
handled = 1;
fec_enet_mii(dev);
}
}
return IRQ_RETVAL(handled);
}
......
......@@ -114,7 +114,7 @@ extern int fmv18x_probe(struct net_device *dev);
static int fmv18x_probe1(struct net_device *dev, short ioaddr);
static int net_open(struct net_device *dev);
static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void net_rx(struct net_device *dev);
static void net_timeout(struct net_device *dev);
static int net_close(struct net_device *dev);
......@@ -423,7 +423,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
/* The typical workload of the driver:
Handle the network interface interrupts. */
static void
static irqreturn_t
net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
......@@ -476,7 +476,7 @@ net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
spin_unlock(&lp->lock);
}
}
return;
return IRQ_RETVAL(status);
}
/* We have a good packet(s), get it/them out of the buffers. */
......
......@@ -199,7 +199,7 @@ static void z8530_init(void);
static void init_channel(struct scc_channel *scc);
static void scc_key_trx (struct scc_channel *scc, char tx);
static void scc_isr(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs);
static void scc_init_timer(struct scc_channel *scc);
static int scc_net_setup(struct scc_channel *scc, unsigned char *name, int addev);
......@@ -625,7 +625,7 @@ static void scc_isr_dispatch(struct scc_channel *scc, int vector)
#define SCC_IRQTIMEOUT 30000
static void scc_isr(int irq, void *dev_id, struct pt_regs *regs)
static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned char vector;
struct scc_channel *scc;
......@@ -653,7 +653,7 @@ static void scc_isr(int irq, void *dev_id, struct pt_regs *regs)
if (k == SCC_IRQTIMEOUT)
printk(KERN_WARNING "z8530drv: endless loop in scc_isr()?\n");
return;
return IRQ_HANDLED;
}
/* Find the SCC generating the interrupt by polling all attached SCCs
......@@ -701,6 +701,7 @@ static void scc_isr(int irq, void *dev_id, struct pt_regs *regs)
} else
ctrl++;
}
return IRQ_HANDLED;
}
......
......@@ -541,6 +541,7 @@ static irqreturn_t myri_interrupt(int irq, void *dev_id, struct pt_regs *regs)
struct myri_channel *chan = &mp->shmem->channel;
unsigned long flags;
u32 status;
int handled = 0;
spin_lock_irqsave(&mp->irq_lock, flags);
......@@ -549,6 +550,7 @@ static irqreturn_t myri_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (status & ISTAT_HOST) {
u32 softstate;
handled = 1;
DIRQ(("IRQ_DISAB "));
myri_disable_irq(lregs, mp->cregs);
softstate = sbus_readl(&chan->state);
......@@ -568,7 +570,7 @@ static irqreturn_t myri_interrupt(int irq, void *dev_id, struct pt_regs *regs)
spin_unlock_irqrestore(&mp->irq_lock, flags);
return IRQ_HANDLED;
return IRQ_RETVAL(handled);
}
static int myri_open(struct net_device *dev)
......
......@@ -84,7 +84,7 @@ static int seeq8005_probe1(struct net_device *dev, int ioaddr);
static int seeq8005_open(struct net_device *dev);
static void seeq8005_timeout(struct net_device *dev);
static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev);
static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t seeq8005_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void seeq8005_rx(struct net_device *dev);
static int seeq8005_close(struct net_device *dev);
static struct net_device_stats *seeq8005_get_stats(struct net_device *dev);
......@@ -400,11 +400,12 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
/* The typical workload of the driver:
Handle the network interface interrupts. */
static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs)
static irqreturn_t seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
struct net_device *dev = dev_id;
struct net_local *lp;
int ioaddr, status, boguscount = 0;
int handled = 0;
ioaddr = dev->base_addr;
lp = (struct net_local *)dev->priv;
......@@ -416,17 +417,20 @@ static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs)
}
if (status & SEEQSTAT_WINDOW_INT) {
handled = 1;
outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
if (net_debug) {
printk("%s: window int!\n",dev->name);
}
}
if (status & SEEQSTAT_TX_INT) {
handled = 1;
outw( SEEQCMD_TX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
lp->stats.tx_packets++;
netif_wake_queue(dev); /* Inform upper layers. */
}
if (status & SEEQSTAT_RX_INT) {
handled = 1;
/* Got a packet(s). */
seeq8005_rx(dev);
}
......@@ -436,6 +440,7 @@ static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs)
if(net_debug>2) {
printk("%s: eoi\n",dev->name);
}
return IRQ_RETVAL(handled);
}
/* We have a good packet(s), get it/them out of the buffers. */
......
......@@ -124,6 +124,7 @@ static void qe_init_rings(struct sunqe *qep)
qb->qe_rxd[i].rx_flags =
(RXD_OWN | ((RXD_PKT_SZ) & RXD_LENGTH));
}
return IRQ_HANDLED;
}
static int qe_init(struct sunqe *qep, int from_irq)
......
......@@ -201,7 +201,7 @@ static int streamer_open(struct net_device *dev);
static int streamer_xmit(struct sk_buff *skb, struct net_device *dev);
static int streamer_close(struct net_device *dev);
static void streamer_set_rx_mode(struct net_device *dev);
static void streamer_interrupt(int irq, void *dev_id,
static irqreturn_t streamer_interrupt(int irq, void *dev_id,
struct pt_regs *regs);
static struct net_device_stats *streamer_get_stats(struct net_device *dev);
static int streamer_set_mac_address(struct net_device *dev, void *addr);
......@@ -1021,7 +1021,7 @@ static void streamer_rx(struct net_device *dev)
} /* end for all completed rx descriptors */
}
static void streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static irqreturn_t streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) dev_id;
struct streamer_private *streamer_priv =
......@@ -1142,6 +1142,7 @@ static void streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
} /* while() */
spin_unlock(&streamer_priv->streamer_lock) ;
return IRQ_HANDLED;
}
static int streamer_xmit(struct sk_buff *skb, struct net_device *dev)
......
......@@ -2027,7 +2027,7 @@ set_multicast_list(struct net_device *dev)
}
}
return;
return IRQ_HANDLED;
}
/*
......
......@@ -117,7 +117,7 @@ static int lmc_rx (struct net_device *dev);
static int lmc_open(struct net_device *dev);
static int lmc_close(struct net_device *dev);
static struct net_device_stats *lmc_get_stats(struct net_device *dev);
static void lmc_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
static irqreturn_t lmc_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
static int lmc_set_config(struct net_device *dev, struct ifmap *map);
static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base, size_t csr_size);
static void lmc_softreset(lmc_softc_t * const);
......@@ -1388,7 +1388,7 @@ static int lmc_ifdown (struct net_device *dev) /*fold00*/
/* Interrupt handling routine. This will take an incoming packet, or clean
* up after a trasmit.
*/
static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*fold00*/
static irqreturn_t lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*fold00*/
{
struct net_device *dev = (struct net_device *) dev_instance;
lmc_softc_t *sc;
......@@ -1398,6 +1398,7 @@ static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*
unsigned int badtx;
u32 firstcsr;
int max_work = LMC_RXDESCS;
int handled = 0;
lmc_trace(dev, "lmc_interrupt in");
......@@ -1421,6 +1422,8 @@ static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*
/* always go through this loop at least once */
while (csr & sc->lmc_intrmask) {
handled = 1;
/*
* Clear interrupt bits, we handle all case below
*/
......@@ -1580,6 +1583,7 @@ static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*
spin_unlock(&sc->lmc_lock);
lmc_trace(dev, "lmc_interrupt out");
return IRQ_RETVAL(handled);
}
static int lmc_start_xmit (struct sk_buff *skb, struct net_device *dev) /*fold00*/
......
......@@ -329,7 +329,7 @@ void arcnet_dump_packet(struct net_device *dev, int bufnum, char *desc);
#endif
void arcnet_unregister_proto(struct ArcProto *proto);
void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs);
irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs);
void arcdev_setup(struct net_device *dev);
void arcnet_rx(struct net_device *dev, int bufnum);
......
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